Zur Themenübersicht    

5. Der Interpreter



1. UML-Diagramm



2. Der Interpreter

2.1. Arbeitsweise

Zum direkten Ausführen der Tokenliste gibt es mehrere verschiedene Ansätze. Wir haben uns für ein rekursives Vorgehen entschieden.
Vom Hauptprogramm aus wird lediglich der Befehl "fuehreTokenListeAus" aufgerufen. Die lexikalisch und syntaktisch korrekte, als Parameter übergebenen Tokenliste wird dann Tokenweise durchgegangen. Je nach Typ des Tokens wird unterschiedlich verfahren. Wenn es sich um...

2.2. Die wichtigsten Attribute und Methoden der Klasse TInterpreter

Mit dem Konstruktor "init" und dem Desktruktor "gibFrei" kann wie üblich eine Instanz der Klasse erzeugt bzw. vernichtet werden.
Das Attribut "kenntBender" dient als Speicherplatz für die "Kennt-Beziehung" zum Roboter, damit ist es möglich den Roboter direkt anzusprechen.

procedure TInterpreter.fuehreBefehlAus (pBefehl: String);
Diese Methode führt Token des Typs Befehl aus. Dazu wird der übergebene Befehl an Bender weitergeleitet.

function TInterpreter.gibErgebnissVonAnfrage (pAnfrage: String) : Boolean;
Diese Anfrage gibt das Ergebnis von Token des Typs Anfrage zurück. Dazu wird Bender direkt angesprochen.

function TInterpreter.BedingungErfuellt (pBedingung: TTokenListe) : Boolean;
Diese Anfrage gibt das Ergebnis einer Bedingungs-Tokenliste zurück. Diese setzt sich zusammen aus einer Anfrage und einer möglichen Negation durch den Operator not.
Dazu wird das Ergebnis zunächst durch "gibErgebnissVonAnfrage (pAnfrage: String) : Boolean" ermittelt, und gegebenenfalls negiert.

function TInterpreter.gibTokenlisteBisKlammerZu (pTokenListe: TTokenliste; pStartPosition: Integer; VAR endPosition: Integer) : TTokenliste; virtual;
Diese Anfrage geht die als Parameter übergebene Tokenliste soweit durch, bis die an der StartPosition geöffnete Klammer wieder geschlossen wurde (also bis soviele Klammern geschlossen, wie zuvor geöffnet wurden). Der Abschnitt zwischen den beiden Klammern wird als Ergebniss zurückgegeben. Zusätzlich wird die Position der schließenden Klammer in die Speicheradresse "endPosition" geschrieben.

procedure TInterpreter.fuehreSolangeWieAus (pBedingung: TTokenliste; pTueBefehle: TTokenliste);
Hier wird die Tue-Tokenliste solange rekursiv an "fuehreTokenlisteAus" weitergegeben wie die Bedingungs-Tokenliste erfüllt ist.

procedure TInterpreter.fuehreWennAus (pBedingung: TTokenListe; pDannBefehle: TTokenliste; pSonstBefehle: TTokenliste);
Hier wird je nach Ergebniss der Bedingungs-Tokenliste entweder die Dann- oder die Sonst-Tokenliste rekursiv an "fuehreTokenlisteAus" weitergegeben.

procedure TInterpreter.fuehreTokenlisteAus (pTokenListe: TTokenliste);
In dieser Methode wird die als Parameter übergebenen Tokenliste wie oben beschrieben ausgeführt. Dazu werden die Token (und die eventuell bebötigten Folgetoken) und die Methoden "fuehre...Aus" verteilt.

2.3. Entscheidende und interessante Codestellen







Solange wie noch nicht das Ende der
Tokenliste erreicht ist...

Informationen des aktuellen Token
zwischen speichern

Wenn es ein Befehl ist, dann direkt
ausführen


Wenn es ein Solange-Wie Anweisung ist, dann...

...in Abhängigkeit von not zuerst Bedingungs-Tokenliste
erstellen
...die folgenden Anweisungen bis die enstsprechende Klammer
wieder geschlossen wird in tue-Tokenliste schreiben







...die beiden erstellten Tokenlisten an die Methode zum
Ausführen von Solange-Wie Anweisungen weiterleiten



Wenn es ein Wenn-Dann Anweisung ist, dann...

...in Abhängigkeit von not zuerst Bedingungs-Tokenliste
erstellen
...die folgenden Anweisungen bis die entsprechende Klammer
wieder geschlossen ist, wird in Dann-Tokenliste schreiben








...sofern noch ein Sonst-Teil vorhanden ist, die folgenden Anweisungen bis die enstsprechende Klammer wieder geschlossen wird in Sonst-Tokenliste schreiben


...die erstellten Tokenlisten an die Methode zum
Ausführen von Wenn-Dann Anweisungen weiterleiten

procedure TInterpreter.fuehreTokenlisteAus (pTokenListe: TTokenliste);
var
  position : Integer;
  Befehl, BefehlsTyp : String;
  Bedingung, TueBefehle, DannBefehle, SonstBefehle: TTokenliste;
begin
  position := 0;

  while position < Length(pTokenListe) do
  begin
    Befehl := pTokenListe[position][2];
    BefehlsTyp := pTokenListe[position][1];


    //--Befehl--
    if BefehlsTyp = 'befehl'
      then fuehreBefehlAus(befehl)


    //--SolangeWie-Anweisung--
    else if Befehl = 'solangewie' then
    begin
      if pTokenListe[position + 1][2] = 'not' then
      begin
        SetLength(Bedingung,2);
        Bedingung[0][2] := 'not';
        Bedingung[1][2] := pTokenListe[position + 2][2];
        TueBefehle := self.gibTokenlisteBisKlammerZu(pTokenListe,position + 4, position);
        //Hierbei wird die Variable position automatisch auf die 
        //Position der geschlossenen Klammer gestzt
      end
      else
      begin
        SetLength(Bedingung,1);
        Bedingung[0][2] := pTokenListe[position + 1][2];
        TueBefehle := self.gibTokenlisteBisKlammerZu(pTokenListe,position + 3, position);
      end;
      fuehreSolangeWieAus(Bedingung,tueBefehle);
    end


    //--Wenn-Dann-Anweisung--
    else if Befehl = 'wenn' then
    begin
      if pTokenListe[position + 1][2] = 'not' then
      begin
        SetLength(Bedingung,2);
        Bedingung[0][2] := 'not';
        Bedingung[1][2] := pTokenListe[position + 2][2];
        DannBefehle := self.gibTokenlisteBisKlammerZu(pTokenListe,position + 4, position);
      end
      else
      begin
        SetLength(Bedingung,1);
        Bedingung[0][2] := pTokenListe[position + 1][2];
        DannBefehle := self.gibTokenlisteBisKlammerZu(pTokenListe,position + 3, position);
      end;

      SetLength(SonstBefehle,0);
      if position + 1 < length(pTokenListe) then
      begin
        if pTokenListe[position + 1][2] = 'sonst'
          then SonstBefehle := self.gibTokenlisteBisKlammerZu(pTokenListe,position + 2, position);
      end;

      fuehreWennAus(Bedingung,DannBefehle,sonstBefehle);
    end;

    position := position + 1;
  end;
end;



Wenn die Bedingung erfüllt ist...
...wird die Dann-Tokenliste ausgeführt

...sonst wird die Sonst-Tokenliste ausgeführt

procedure TInterpreter.fuehreWennAus (pBedingung: TTokenListe; pDannBefehle: TTokenliste; pSonstBefehle: TTokenliste);
begin
  if BedingungErfuellt(pBedingung)

    then fuehreTokenlisteAus(pDannBefehle)


    else fuehreTokenlisteAus(pSonstBefehle);
end;






Sofern keine Klammern gefunden werden, wird
nichts zurückgegeben und die endPosition bleibt
die Startposition.

Wenn wirklich eine Klammer an "StartPosition" geöffnet
wurde, dann



Wiederhole solange bis alle geöffneten Klammer
geschlossen wurden...
...füge den aktuellen Token zum result hinzu

...falls eine Klammer geöffnet wurde zähle KlammerAuf
   um eins hoch
...falls eine Klammer geschlossen wurde zähle KlammerZu
   um eins hoch


...gehe zum nächsten Token


Am Ende wird die letzte geschlossene Klammer aus dem Result
entfernt, da die erste geöffnete auch nicht drin steht
function TInterpreter.gibTokenlisteBisKlammerZu (pTokenListe: TTokenliste; pStartPosition: Integer;
                                                 VAR endPosition: Integer) : TTokenliste;
var
  KlammerAuf, KlammerZu : Integer;
  position : Integer;
begin
  setLength(result,0);
  endPosition := pStartPosition;
  KlammerAuf := 0;
  KlammerZu := 0;


  position := pStartPosition;
  if pTokenliste[position][2] = '{' then
  begin
    KlammerAuf := 1;
    position := pStartPosition + 1;
    while KlammerAuf <> KlammerZu do
    begin
      setlength(result, length(result) + 1);
      result[length(result) - 1][2] := pTokenListe[position][2];
      result[length(result) - 1][1] := pTokenListe[position][1];
      if pTokenListe[position][2] = '{'
        then KlammerAuf := KlammerAuf + 1
     
        else if pTokenListe[position][2] = '}'
               then KlammerZu := KlammerZu + 1;



      position := position + 1;
    end;

    setlength(result, length(result) - 1);
    position := position - 1;
    endPosition := position;
  end;
end;