ldn schrieb:
> Es klappt eig ganz gut, nur:
> Infix: (2+30)*4^25 <-- Eingabe
> Postfix: 230+425^* <-- Ausgabe
> Man sieht: die Zahlen werde nicht richtig getrennt. Ist ja uach klar,
> ich füge nirgends ein ' ' ein. Nur ich weiß jetzt nicht wie, oder eher
> wo, ich das Leerzeichen einfügen muss.
Das kannst du so auch nicht, denn du unterscheidest in deiner
übergeordneten Schleife hier
1 | while (*term) {
|
2 | if (isalnum(*term))
|
3 | *buffer++ = *term;
|
4 | ...
|
nicht, ob damit eine Zahl komplett ist oder nicht, sondern du behandelst
das alles, als ob immer nur 1 Zeichen relevant ist.
Mit anderen Worten: dein Parser kann nicht erkennen, dass eine 'Einheit'
(Zahl, Variablennamen, Operator, ...) aus mehreren Zeichen bestehen
könnte, sondern geht immer davon aus, dass es sich beim nächsten zu
parsenden Symbol um genau 1 Zeichen handelt.
Deshalb agieren echte Parser auch nicht in dieser Form direkt auf dem
Quelltext sondern benutzen einen sog. lexikalischen Parser, der ihnen
das jeweils nächste Symbol zum Parsen heraus holt. So ein lexiaklischer
Parser untersucht die jeweils nächsten Ccaracter aus der EIngabe und
stellt zb fest, dass da jetzt 3 Ziffer-Character hintereinander kommen,
die er zu einer Zahl zusammenfassen soll. Der Syntaxparser kriegt vom
lexikalischen Parser dann die Information, dass als nächstes Symbol in
der Eingabe eine Zahl vorhanden ist (deren Wert beispielsweise 385
beträgt), oder das in der EIngabe als nächstes Symbol ein 'kleiner
gleich' Symbol vorhanden ist.
D.h. für den Parser gestaltet sich die Extraktion des nächsten Symbols
aus der Eingabe nicht mehr so einfach
dadurch, dass er *term betrachtet, sondern er überlässt diese Analyse
dem lexikalischen Parser, der sich die jeweils nächsten Character
ansieht und entscheidet ob und wie die zusammenghören
1 | while ( nextSymbol( &term, &sym, &value ) ) {
|
2 |
|
3 | if( sym == NUMBER )
|
4 | push_number( value );
|
5 |
|
6 | else if( sym == OPERATOR )
|
7 | push_operator( value ); // value ist ein Code für beispielsweise die + Operation
|
8 | ....
|
Jetzt wird dein ganzer Aufbau schon ein wenig komplexer, weil du nicht
einfach nur 1-buchstabige Dinge auf deinem Stack verwalten musst,
sondern weil da jetzt ein buntes Mischmasch aus Zahlen und Operationen
auf dem Stack verwaltet werden muss.
Dazu brauchst du aber dann auch eine entsprechende Datenstruktur, mit
der du das kannst. Dein Stack ist dann nicht mehr einfach nur ein Array
von char. Sondern dein Stack könnte dann zb so aussehen
1 | struct exprStackItem
|
2 | {
|
3 | unsigned char itemType;
|
4 | int itemValue;
|
5 | };
|
6 |
|
7 | struct exprStackItem exprStack[50]; // Platz für 50 einträge am Stack
|
8 | int exprStackPointer;
|
9 |
|
10 | #define STACK_NUMBER_ITEM 1
|
11 | #define STACK_OPERATOR_ITEM 2
|
12 | #define STACK_OPEN_PAREN_ITEM 3
|
13 |
|
14 | void pushNumber( int value )
|
15 | {
|
16 | exprStack[exprStackPointer].itemType = STACK_NUMBER_ITEM;
|
17 | exprStack[exprStackPointer++].itemValue = value;
|
18 | }
|
19 |
|
20 | void pushOperator( int operatorCode )
|
21 | {
|
22 | exprStack[exprStackPointer].itemType = STACK_OPERATOR_ITEM;
|
23 | exprStack[exprStackPointer++].itemValue = value;
|
24 | }
|
25 |
|
26 | void pushOpenParen( void )
|
27 | {
|
28 | exprStack[exprStackPointer].itemType = STACK_OPEN_PAREN_ITEM;
|
29 | }
|
30 |
|
31 | ....
|
Aber: dadurch, dass du die Dinge jetzt sauber auf dem Stack liegen hast,
kannst du zb die angegebenen Ausdrücke auch tatsächlich irgendwann
ausrechnen. Dein eine Integer-Zahl ist bei dir am Stack jetzt auch
wirklich eine Integer Zahl und nicht einfach nur einzelne 'Buchstaben'.