Die Syntax, die du dir da ausgedacht hast, ist schlecht, weil sie nicht
LL(1) ist.
Kurz gesagt: wenn du als nächstes Symbol von der Eingabe ein / einliest,
dann kannst du nicht unterscheiden, ob es sich dabei um eine Division
oder um einen Bruchstrich für eine CFraction handelt.
Theoretisch (mathematisch) sollte das egal sein, weil ein Bruch auch
nichts anderes als eine Division ist. Bei dir aber nicht.
d.h. du unterscheidest zwischen
und
und das ist schlecht. Denn welcher Fall vorliegt kannst du erst
entscheiden, nachdem du in 5/2 die zweite Zahl gesehen hast. Die
Ansicht: ja, aber im ersten Fall sind ja keine Leerzeichen vorhanden ist
keine gute Entscheidung. Auf Leerzeichen zu setzen ist für einen
Benutzer recht fehleranfällig, da kein Mensch einsieht, warum
und
bzw
verschiedene Dinge sein sollen.
Weiters: Wie ist
korrekt zu interpretieren? Ist das nun
oder ist es
deine Schreibweise wäre nicht eindeutig in diesem Punkt, wenn du
Fractions zulässt.
Ansonsten ist sowas eine Standardübung in der ersten Hälfte der
Vorlesung "Compilerbau". Alles beginnt damit, dass man die EIngabe
zunächst in Symbole zerlegt. Man macht sich eine Funktion, die die
Eingabe verwaltet und bei jedem Aufruf das jeweils nächste Symbol
liefert. Symbole sind bei dir 'Number, Plus, Minus, Times, Divide' (ich
ignoriere mal deine Fractions). Da deine Notataion bereits UPN ist und
du auch UPN erzeugen musst, ist das ganze nicht viel mehr als eine Übung
in der Stringverarbeitung.
Die Hauptfunktion sieht ungefähr so aus
1 | #define numSym 1
|
2 | #define plusSym 2
|
3 | #define minusSym 3
|
4 | #define timesSym 4
|
5 | #define divideSym 5
|
6 | #define eofSym 99
|
7 | ....
|
8 |
|
9 | char InputString[80];
|
10 | int nextChar;
|
11 |
|
12 | ....
|
13 |
|
14 | strcpy( InputString, "5 8 *" );
|
15 | nextChar = 0;
|
16 |
|
17 |
|
18 | sym = nextSym( &number );
|
19 |
|
20 | while( sym != eofSym )
|
21 | {
|
22 | if( sym == numSym )
|
23 | {
|
24 | sprintf( buff, "pushValue(CFraction(%d,1);\n", number );
|
25 | emit( buff );
|
26 | }
|
27 |
|
28 | else if( sym == plusSym )
|
29 | emit( "add();\n" );
|
30 |
|
31 | else if( sym == minusSym )
|
32 | emit( "subtract();\n" );
|
33 |
|
34 | else if( sym == timesSym )
|
35 | emit( "multiply();\n" );
|
36 |
|
37 | else if( sym == divideSym )
|
38 | emit( "divide();\n" );
|
39 | }
|
40 |
|
41 | emit( "popResult(result);\n" );
|
42 | emit( "cout << result;\n" );
|
43 |
|
44 | ....
|
dann brauchst du noch eine Funktion nextSym, die aus dem Eingabestring
das nächste Symbol bestimmt.
Das geht so: die Funktion (Klasse) merkt sich, an welcher Stelle im
String sie zuletzt aufgehört hat.
Dort macht sie beim nächsten Aufruf weiter.
Zunächst werden alle Leerzeichen überlesen. Mit dem nächsten Zeichen im
String entscheidest du dann: ist es ein '+', '-', '*', '/' dann liefert
die Funktion das zugehörige Symbol. Ist das nächste Zeichen aber eine
Ziffer ('0' bis '9'), dann ist das der Anfang einer Zahl. du liest
solange Zeichen weiter, wie sie Ziffern sind und setzt die Zahl dabei
zusammen, während die Ziffern auftauchen. Getreu der Vorschrift
1 | Zahl = 10*Zahl + Ziffer - '0';
|
also ca so
1 | int nextSym( int* number )
|
2 | {
|
3 | while( InputString[nextChar] == ' ' )
|
4 | nextChar++;
|
5 |
|
6 | nChar = InputString[nextChar++];
|
7 |
|
8 | switch( nChar )
|
9 | {
|
10 | case '+':
|
11 | return plusSym;
|
12 | break;
|
13 |
|
14 | case '-':
|
15 | return minusSym;
|
16 | break;
|
17 |
|
18 | case '*':
|
19 | return timesSym;
|
20 | break;
|
21 |
|
22 | case '/':
|
23 | return divideSym;
|
24 | break;
|
25 | }
|
26 |
|
27 | *number = 0;
|
28 | while( nChar >= '0' && nChar <= '9' )
|
29 | *number = *number * 10 + nChar - '0';
|
30 | return numberSym;
|
31 | }
|
(Fehlerbehandlung bzw. Stringende musst du noch ergänzen.