Einzelnen Beitrag anzeigen

PRehders

Registriert seit: 31. Okt 2003
Ort: Hamburg
42 Beiträge
 
#10

Re: wie bearbeitet ein Compiler if-Abfragen?

  Alt 3. Feb 2005, 09:37
Hallo nochmal,

jetzt mal ein bischen was konkretes.

Zuerst: Du brauchst einen Scanner, der dir immer sagt, welcher Art das nächste Zeichen ist.
Und dieses auch aufbereitet. Dies nennt man häufig einen "Tokenizer", da er den Eingabezeichenstrom in sogenannte Tokens zerlegt. Ein solches Token wäre z.B. "Identifier" (Variable), oder "Literal" (irgendeine Zahl, ein Buchstabe in ""), oder "Operator" (+ - * / = <> <= < >= > AND OR NOT) wobei man hier besser alle Operatoren einzelnd benennen sollte, da sie
unterschiedliche Gewichtung haben, schliesslich noch die Klammern "(" und ")", denn die braucht man ja, um den Vorrang der Operatoren zu ändern.
Dein Tokenizer sollte also eine Funktion "next_token()" haben, der immer das nächste Symbol zurückgibt. Für die Symbole nimmst du am besten einen Aufzählungstyp. Wenn er sagt, dass es eine Variable ist, musst er natürlich auf Nachfrage auch sagen, welche denn überhaupt genannt wurde (ähnlich bei einem Literal).

Damit haben wir schon ein gutes Rüstzeug. Ich schreibe jetzt mal Pseudocode für den Fall, dass du den Ausdruck sofort auswerten willst und keinen Baum im Speicher aufbaust. Es gibt für jede Stufe der Auswertung eine Funktion, die mit TRUE zurückgibt, dass alles glattgegangen ist. Per Referenz wird eine Struktur übergeben, die das Ergebnis der Auswertung enthält (eine Struktur deshalb, weil es ja verschiedene Typen etc. geben kann). Nach der Rückkehr einer Function steht der Tokenizer auf dem nächsten Token.

Code:
 function Parse_Expression (VAR ergebnis): Boolean;
 begin
  if parse_SimpleExpression(ergebnisLeft)
   then if akt_token <relationaler Operator>
         then next_token()
              if parse_SimpleExpression (ergebnisRight)
               then return verarbeiteOperator(ergebnisLeft, ergebnisRight, operator, ergebnis);
               else return false
         else return false
   else return false;
 end;

 function Parse_SimpleExpression (VAR ergebnis): Boolean;
 begin
  if parse_Term(ergebnisLeft)
   then if akt_token <additiver Operator>
         then next_token()
              if parse_Term (ergebnisRight)
               then return verarbeiteOperator(ergebnisLeft, ergebnisRight, operator, ergebnis);
               else return false
         else return false
   else return false;
 end;

 function Parse_Term (VAR ergebnis): Boolean;
 begin
  if parse_Faktor(ergebnisLeft)
   then if akt_token <multiplikativer Operator>
         then next_token()
              if parse_Faktor (ergebnisRight)
               then return verarbeiteOperator(ergebnisLeft, ergebnisRight, operator, ergebnis);
               else return false
         else return false
   else return false;
 end;

 function Parse_faktor (VAR ergebnis): Boolean;
 begin
  if akt_token <Literal>
   then ergebnis := <Inhalt des Literals>
   else if akt_Token <Identifier>
         then ergebnis := <Inhalt der Variable>
         else if akt_token <Klammer auf>
               then next_token()
                    if parse_expression(ergebnis)
                     then if akt_token <Klammer zu>
                           then <nix>
                           else return false
                     else return false
               else return false;
  netxt_token();
  return true;
 end;

 function verarbeiteOperator(argument1, argument2, operator, VAR ergebnis):Boolean;
 begin
   <passt der Operator zum Typ der Argumente?>
   <passen die Typen der Argumente zueinander?>
   case Operator of
    "+" : ergebnis := argument1 + argument2
   ...
   end;
 end;
Das ist das Gerüst; wie man verschiedenen Typen umgeht, überlasse ich jetzt mal deiner Phantasie, aber ein RECORD könnte dabei eine Rolle spielen...
Der Trick an der Sache ist der, den Tokenizer zum richtigen Zeitpunkt weitergehen zu lassen. Wenn du es codest und im debugger durchgehst, merkst du aber schnell, wie es läuft.
Durch die Aufspaltung in die einzelnen Funktionen werden alle Informationen in den lokalen Variablen zwischengespeichert, bis sie verwendet werden, wie z.B. der jeweilige Operator.

In deinem Hauptprogramm rufst du dann nur noch auf: if parse_expression(ergebnis) then ... im ergebnis steht dann (hofffentlich) ein boolsches Feld mit dem Ergebnis. Steht im Input allerdings nur ein Teilausdruck wie "a+1", dann kommt natürlich etwas anderes heraus. Also: Abfragen, abfragen, abfragen. In der realen Welt besteht mindestens die Hälfte des
Codes aus Abfragen, ob alles korrekt läuft...

Ich habe es so formuliert, dass ein fehlerhafter Input die gesamte Verarbeitung beendet. Du solltest dich nie darauf verlassen, dass der Input syntaktisch korrekt ist!

Na dann mal viel Spaß!

Peter
Peter Rehders
Man sollte niemanden ernst nehmen, der sich ernst nimmt.
  Mit Zitat antworten Zitat