<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[parserbaum]]></title><description><![CDATA[<p>hallo</p>
<p>ich möchte für ein programm, was einen funktionsgraphen darstellen soll, einen<br />
parserbaum benutzen. das funktioniert zwar, allerdings sehen einige stellen<br />
unschön aus, was wahrscheinlich ein designfehler ist.</p>
<pre><code class="language-cpp">struct node
{
    virtual ~node(){}
    virtual double eval() = 0;
	virtual node **getleft() = 0;
	virtual node **getright() = 0;
	virtual unsigned getpriority() = 0;
};
</code></pre>
<p>davon erben klassen wie add, sub, mul... etc, die einfach nur ihre<br />
child-zeiger kapseln und diese auswerten können.<br />
exemplarisch man die &quot;add&quot; klasse:</p>
<pre><code class="language-cpp">class add : public node
{
public:
    add(node *n1, node *n2)
    {
		left = n1;
        right = n2;
    }
    ~add()
    {
        delete right;
        delete left;
    }
    double eval()
    {
        return left-&gt;eval() + right-&gt;eval();
    }
	node **getleft()
	{
		return &amp;left;
	}
	node **getright()
	{
		return &amp;right;
	}
	unsigned getpriority()
	{
		return 1;
	}
private:
    node *left, *right;
};
</code></pre>
<p>um den baum aufzubauen nutze ich folgende funktion (gekürtzt):</p>
<pre><code class="language-cpp">node *build(const char *&amp;str, const char *end)
{
	node *n = 0;
    while (str != end)
    {
		if (*str &lt;= '9' &amp;&amp; *str &gt;= '0')
		{
			double val = 0.0;
			// val einlesen
			n = new num(val);
		}
        else if (*str == '+')
		{
			if (!n)
				n = new num(0.0);

			node *right = build(++str, end);
			if (!right)
			{
				delete n;
				return 0;
			}
			n = new add(n, right);
		}
		else if (*str == '-')
		{
			// subtraktion
		}
		else if (*str == '*')
		{
			if (!n)
				return 0;

			node *right = build(++str, end);
			if (!right)
			{
				delete n;
				return 0;
			}
			n = new mul(n, right);
			n = correct(n, right); // &lt;---
		}
		else if (*str == '(')
		{
			// klammern
		}
    }
	return n;
}
</code></pre>
<p>auch das funktioniert, allerdings wird nur die reihenfolge beachtet<br />
und nicht die priorität. deshalb muss man manuell nachhelfen:</p>
<pre><code class="language-cpp">node *correct(node *a, node *b)
{
	if (a-&gt;getpriority() == b-&gt;getpriority())
		return a;

	node *child1 = *a-&gt;getleft();
	node *child2 = a-&gt;getpriority() &lt; b-&gt;getpriority() ? *a-&gt;getright() : *b-&gt;getleft();
	node *child3 = *b-&gt;getright();
	if (!child1 || !child2 || !child3)
		return a;

	if (a-&gt;getpriority() &gt; b-&gt;getpriority())
	{
		node *temp = a;
		a = b;
		b = temp;
		temp = child1;
		child1 = child3;
		child3 = temp;
	}

	*a-&gt;getleft() = child1;
	*a-&gt;getright() = b;
	*b-&gt;getleft() = child2;
	*b-&gt;getright() = child3;
	return a;
}
</code></pre>
<p>frage: geht das auch einfacher? wie sollte man den baum aufbauen?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/237576/parserbaum</link><generator>RSS for Node</generator><lastBuildDate>Wed, 23 Sep 2026 09:33:56 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/237576.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 30 Mar 2009 21:53:29 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to parserbaum on Mon, 30 Mar 2009 21:53:29 GMT]]></title><description><![CDATA[<p>hallo</p>
<p>ich möchte für ein programm, was einen funktionsgraphen darstellen soll, einen<br />
parserbaum benutzen. das funktioniert zwar, allerdings sehen einige stellen<br />
unschön aus, was wahrscheinlich ein designfehler ist.</p>
<pre><code class="language-cpp">struct node
{
    virtual ~node(){}
    virtual double eval() = 0;
	virtual node **getleft() = 0;
	virtual node **getright() = 0;
	virtual unsigned getpriority() = 0;
};
</code></pre>
<p>davon erben klassen wie add, sub, mul... etc, die einfach nur ihre<br />
child-zeiger kapseln und diese auswerten können.<br />
exemplarisch man die &quot;add&quot; klasse:</p>
<pre><code class="language-cpp">class add : public node
{
public:
    add(node *n1, node *n2)
    {
		left = n1;
        right = n2;
    }
    ~add()
    {
        delete right;
        delete left;
    }
    double eval()
    {
        return left-&gt;eval() + right-&gt;eval();
    }
	node **getleft()
	{
		return &amp;left;
	}
	node **getright()
	{
		return &amp;right;
	}
	unsigned getpriority()
	{
		return 1;
	}
private:
    node *left, *right;
};
</code></pre>
<p>um den baum aufzubauen nutze ich folgende funktion (gekürtzt):</p>
<pre><code class="language-cpp">node *build(const char *&amp;str, const char *end)
{
	node *n = 0;
    while (str != end)
    {
		if (*str &lt;= '9' &amp;&amp; *str &gt;= '0')
		{
			double val = 0.0;
			// val einlesen
			n = new num(val);
		}
        else if (*str == '+')
		{
			if (!n)
				n = new num(0.0);

			node *right = build(++str, end);
			if (!right)
			{
				delete n;
				return 0;
			}
			n = new add(n, right);
		}
		else if (*str == '-')
		{
			// subtraktion
		}
		else if (*str == '*')
		{
			if (!n)
				return 0;

			node *right = build(++str, end);
			if (!right)
			{
				delete n;
				return 0;
			}
			n = new mul(n, right);
			n = correct(n, right); // &lt;---
		}
		else if (*str == '(')
		{
			// klammern
		}
    }
	return n;
}
</code></pre>
<p>auch das funktioniert, allerdings wird nur die reihenfolge beachtet<br />
und nicht die priorität. deshalb muss man manuell nachhelfen:</p>
<pre><code class="language-cpp">node *correct(node *a, node *b)
{
	if (a-&gt;getpriority() == b-&gt;getpriority())
		return a;

	node *child1 = *a-&gt;getleft();
	node *child2 = a-&gt;getpriority() &lt; b-&gt;getpriority() ? *a-&gt;getright() : *b-&gt;getleft();
	node *child3 = *b-&gt;getright();
	if (!child1 || !child2 || !child3)
		return a;

	if (a-&gt;getpriority() &gt; b-&gt;getpriority())
	{
		node *temp = a;
		a = b;
		b = temp;
		temp = child1;
		child1 = child3;
		child3 = temp;
	}

	*a-&gt;getleft() = child1;
	*a-&gt;getright() = b;
	*b-&gt;getleft() = child2;
	*b-&gt;getright() = child3;
	return a;
}
</code></pre>
<p>frage: geht das auch einfacher? wie sollte man den baum aufbauen?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1688484</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1688484</guid><dc:creator><![CDATA[bäumchenparser]]></dc:creator><pubDate>Mon, 30 Mar 2009 21:53:29 GMT</pubDate></item><item><title><![CDATA[Reply to parserbaum on Tue, 31 Mar 2009 13:45:51 GMT]]></title><description><![CDATA[<p>*push*</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1688826</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1688826</guid><dc:creator><![CDATA[pushpush]]></dc:creator><pubDate>Tue, 31 Mar 2009 13:45:51 GMT</pubDate></item><item><title><![CDATA[Reply to parserbaum on Wed, 01 Apr 2009 00:05:54 GMT]]></title><description><![CDATA[<p>Zu der Node könntest du noch eine Oberklasse &quot;BinaryOperator&quot; oder so deklarieren, welche die Verwaltung des linken und rechten Knotens übernimmt. Oder du machst überhaupt keine spezifischen Klassen für die einzelnen Knoten, sondern gibst einer flexiblen BinaryOperator-Klasse die eval-Funktion als Funktionszeiger mit, zusätzlich die Priorität (obwohl man die imho gar nicht in der Klasse braucht).</p>
<p>bäumchenparser schrieb:</p>
<blockquote>
<p>wie sollte man den baum aufbauen?</p>
</blockquote>
<p>Ich bin leider kein Parser-Experte und kenne auch nur zwei Möglichkeiten:</p>
<p>a) Du lässt dir den Baum generieren, indem du einem Compiler-Compiler (z.B. <a href="http://de.wikipedia.org/wiki/Lex_(Informatik)" rel="nofollow">Lex</a> + <a href="http://de.wikipedia.org/wiki/Yacc" rel="nofollow">Yacc</a>) die Syntax angibst und dieser dir daraus C(++) Sourcecode generiert.</p>
<p>b) Der selbe Weg zu Fuß: Du unterteilst den Input-Sourcecode in Tokens (ein Token besteht aus der <em>Art</em>:Keyword/Operator/Quote/... und dem zugehörigen Text/Wert) und baust dann aus der Token-Liste die Strukturen und Parserbäume auf. Eine primitive Methode dabei wäre, jeweils die Token-Liste nach dem höchstwertigen Operator zu durchsuchen und an diesen Links und Rechts die Knoten dranzuhängen, die sich bei einem rekursiven &quot;buildTree&quot;-Aufruf mit dem linken bzw rechten Teilstück ergeben.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1689091</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1689091</guid><dc:creator><![CDATA[Badestrand]]></dc:creator><pubDate>Wed, 01 Apr 2009 00:05:54 GMT</pubDate></item><item><title><![CDATA[Reply to parserbaum on Wed, 01 Apr 2009 08:58:03 GMT]]></title><description><![CDATA[<p>Du kannst hier auch gern im Forum suchen, das Thema gab es schon oefters. Lex+Yacc parsen nur deinen Ausdruck, den Gleichungsbaum musst du dir schon selbst erzeugen. Mit Lex+Yacc ist es aber viel einfacher. Die Tutorials sind dahingehend recht gut. Die frei Variante heisst flex + bison.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1689159</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1689159</guid><dc:creator><![CDATA[knivil]]></dc:creator><pubDate>Wed, 01 Apr 2009 08:58:03 GMT</pubDate></item><item><title><![CDATA[Reply to parserbaum on Wed, 01 Apr 2009 09:06:53 GMT]]></title><description><![CDATA[<p>Es gibt auch Parsergeneratoren, die Syntaxbäume erstellen können, z.B. ANTLR. Hab ich aber noch nicht benutzt.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1689166</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1689166</guid><dc:creator><![CDATA[Bashar]]></dc:creator><pubDate>Wed, 01 Apr 2009 09:06:53 GMT</pubDate></item></channel></rss>