wegen
if pos0('*',s)>0 ...
weiss das Programm, das es hier multiplizieren muss. Wenn das Quadrat zerlegt wird schreibt der Parser entsprechend
if pos0('^',s)>0 then result:=power(TTR(anfang(s,'^')),TTR(ende(s,'^')))
das Ergebnis wird also direkt nach rekursiver Termbestimmung berechnet, er braucht sich nicht merken welche arithmetische Operation hier ausgeführt wird, das wird gleich gemacht. Beachte das durch die Rekursion die beiden Terme die man für die jeweilige Operation braucht, bereits explizit berechnet sind.
Zitat von
Penelopee:
Also wenn ich das jetzt richtig verstanden habe, würde das für folgendes Beispiel folgendermaßen ablaufen:
String: '2*x^3+1'
and diesem Bleistift gehen wir mal die Rekursion durch
-
1. Schritt
if pos0('+',s)>0 then TTR(anfang(s,'+'))+TTR(ende(s,'+'))
der Term 1.1 ist noch kein Atomstring, also wird der weiter zerlegt
2. Schritt
if pos0('*',s)>0 then TTR(anfang(s,'*'))*TTR(ende(s,'*'))
der Term 2.1 ist ein Atomstring, der Term 2.2 wird weiter zerlegt
3. Schritt
if pos0('^',s)>0 then result:=power(TTR(anfang(s,'^')),TTR(ende(s,'^')))
die Potenz wird berechnet und zurück zum 2. Schritt gesprungen. Das Ergebnis der Operation hier ist das Funktionsergebnis von TTR(ende(s,'*')).
2. Schritt zum zweiten
Term 2.1 ist bekannt, Term 2.2 wurde gerade zurückgeliefert also kann gerechnet werden und das jetzige Ergebnis geht als Rückgabewert des Aufrufs TTR(anfang(s,'+')) zurück nach Schritt 1
1 Schritt zum zweiten
Term 1.1 ist nun berechnet, Term 1.2 ist ein Atomstring und kann nun direkt addiert werden.
Jetzt liegt das Endergebnis vor und wird an das aufrufende Hauptprogramm zurückgeliefert.
-
im 1. Schritt muss gar nichts zwischengespeichert werden, im 2. Schritt wird der Term 2.1, also der Atomstring kurz auf den Stack gelegt, dann zur Auswertung der Potenz gesprungen. Wenn dieser Funktionsaufruf zurückkehrt wird der Term 2.1 vom Stack geholt und mit dem Ergebnis der Potenz multipliziert.
Der Stack ist hier nur ein ganz normaler Speicher für kurzzeitig zu sichernde Zwischenwerte. Genauso verhält es sich mit den Adressen der Funktionsaufrufe. Springst du zum Beispiel aus Schritt 2 heraus zum 3. Schritt (zum potenzieren) merkt sich das Programm die Adresse (den Ort von wo losgesprungen wird). Das diese Adresse dabei auf den Stack kommt ist eigentlich auch nebensächlich
Wurde die Potenz dann berechnet wird die letzte Adresse vom Stack gelesen und eben dorthin zurückgesprungen. Auf dem Stack liegen natürlich noch andere Adressen von Funktionsaufrufen. Aber es wird immer die letzte Adresse verwendet (und dann der 'Stackpointer', das ist ein Zeiger auf den Stack, korrigiert).
Operationen wie 'multipliziere' werden nie auf den Stack gelegt oder gespeichert, die werden direkt berechnet. Eben durch den rekursiven Aufbau des Parsers wird ja sichergestellt das beide benötigten Terme als Atomstrings zurückgeliefert werden und direkt berechnet werden können. Diese Berechnung liefert nun einen nächsten Atomstring der zur vorherigen Operation zurückgegeben wird oder eben das Endergebnis des Gesamtaufrufes darstellt.
noch'n Bleistift:
if pos0('+',s)>0 then TTR(anfang(s,'+'))+TTR(ende(s,'+'))
TTR(anfang(s,'+')) stellt den Aufruf einer Funktion dar. Durch die Rekursion ergibt der Rückgabewert dieser Funktion einen Atomstring (oder einfach eine Zahl, je nach Auffassung). Dieser Atomstring kommt auf den Stack. Nun wird der 2. Funktionswert durch den Aufruf von TTR(ende(s,'+')) bestimmt, ebenso rekursiv, und ebenso ist der Rückgabewert wieder ein Atomstring. Nun wird die Addition explizit ausgeführt und der neue Atomstring ist fertig und wird wieder zurückgegeben.
ich hoffe jetzt wird's klarer
mfg
Matthias