Benutzer-Werkzeuge

Webseiten-Werkzeuge


compilerbau:erweiterung:start

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
Nächste ÜberarbeitungBeide Seiten der Revision
compilerbau:erweiterung:start [2021/10/28 21:12] – [Erweiterung der Grammatik] Martin Pabstcompilerbau:erweiterung:start [2021/10/28 21:23] – [Erweiterung des Lexers] Martin Pabst
Zeile 41: Zeile 41:
  
 </code> </code>
 +
 +===== Neue Tokentypen =====
 +Für die neuen syntaktischen Elemente brauchen wir zusätzliche Tokentypen:
 +
 +<code java>
 +public enum TokenType {
 +  zahl, text, plus, minus, mal, geteilt, klammerAuf, klammerZu, 
 +  geschweifteKlammerAuf, geschweifteKlammerZu,
 +  whileKeyword, printKeyword,
 +  kleiner, groesser, identisch, kleinergleich, groessergleich, ungleich,
 +  zuweisung,
 +  trueKeyword, falseKeyword,
 +  strichpunkt,
 +
 + /**
 + * Nur als Knotentyp für Knoten des Syntaxbaums:
 + */
 +  negation
 +}
 +</code>
 +
 +===== Erweiterung des Lexers =====
 +Damit der Lexer die Schlüsselwörter ''while'', ''print'', ''true'' und ''false'' erkennt, erweitern wir einfach die Methode ''lexText()'':
 +
 +<code java>
 + /**
 + * Die Methode lexText lext Variablenbezeichner und Schlüsselwörter (keywords)
 + */
 +  private void lexText() {
 +
 +    String text = "";
 +
 +    do {
 +      char c = peek();
 +      text += c;
 +      position++;
 +    } while(istBuchstabe(peek()) || istZiffer(peek()) || peek() == '_');
 +
 +    switch(text) {
 +        case "true"
 +          tokenListe.add(new Token(TokenType.trueKeyword));
 +          break;
 +        case "false"
 +          tokenListe.add(new Token(TokenType.falseKeyword));
 +          break;
 +        case "while"
 +          tokenListe.add(new Token(TokenType.whileKeyword));
 +          break;
 +        case "print"
 +          tokenListe.add(new Token(TokenType.printKeyword));
 +          break;
 +        default : 
 +          tokenListe.add(new Token(text));
 +          break;
 +    }
 +
 +  }
 +</code>
 +
 +Etwas trickreicher sind die neuen Zeichen. Um etwa ''<'' und ''< ='' unterscheiden zu können, muss der Lexer ein Zeichen nach vorne blicken können. Wir brauchen daher eine zusätzliche ''peek(int n)''-Methode, die ''n'' Zeichen nach vorne blickt:
 +
 +<code java>
 + /**
 + * peek(n) liest das Zeichen im Programmtext an (aktuelle Position + n). Die
 + * aktuelle Position (Attribut position) wird nicht verändert.
 +
 + * @return Das Zeichen, das n Zeichen weiter steht als die aktuelle Position
 + */
 +  private char peek(int n) {
 +    if(position + n < text.length()) {
 +      return text.charAt(position + n);
 +    } else {
 +      return(char) 0;
 +    }
 +  }
 +</code>
 +
 +Damit sieht die Erkennung von ''>'', ''>='' und ''!='' so aus:
 +
 +<code java>
 +case '>'
 + if(peek(1) == '=') {
 + addToken(TokenType.groessergleich);
 + position++;
 + } else {
 + addToken(TokenType.groesser);
 + }
 + break;
 +case '!'
 + if(peek(1) == '=') {
 + addToken(TokenType.ungleich);
 + position++;
 + } else {
 + println("Das Zeichen = wird erwartet.", Color.red);
 + System.exit(1);
 + }
 + break;
 +</code>
 +
 +
 +===== Test des Lexers =====
 +Der Lexer lässt sich wieder mit der Klasse ''LexerTest'' testen. Den Programmtext oben zerlegt er beispielsweise in folgende Token:
 +<code>
 +text[a] zuweisung zahl[1.0] strichpunkt text[b] zuweisung zahl[2.0] strichpunkt whileKeyword klammerAuf text[a] kleiner zahl[10.0] klammerZu geschweifteKlammerAuf text[a] zuweisung text[a] plus zahl[1.0] strichpunkt text[b] zuweisung text[b] mal zahl[2.0] strichpunkt printKeyword klammerAuf text[b] klammerZu strichpunkt geschweifteKlammerZu
 +</code>
 +
 +
 +===== Erweiterung der Klasse Knoten =====
 +Auch Anweisungen (Wiederholung, Zuweisung, Print-Anweisung) werden im Syntaxbaum als Knoten dargestellt. Dafür wird neben den Kindknoten ''rechts'' und ''links'' noch ein dritter KindKnoten ''naechsteAnweisung'' benötigt:
 +
 +<code java>
 +public class Knoten {
 +
 + /**
 + * Im Token steckt der Inhalt des Knotens drin, also ein Operator, eine Zahl oder ein 
 + * Variablenbezeichner. Der Einfachheit halber verwenden wir hier die Klasse Token. 
 + */
 + private Token token; 
 +
 + /**
 + * Kindknoten linkerhand
 + */
 + private Knoten links;
 +
 + /**
 + * Kindknoten rechterhand
 + */
 + private Knoten rechts;
 +
 + /**
 + * Im Falle einer Anweisung: nächstfolgende Anweisung
 + */
 + private Knoten naechsteAnweisung;
 +
 +
 +...
 +</code>
 +
 +Die Kindknoten der Anweisungen haben für verschiedene Arten von Anweisungen verschiedene Bedeutung:
 +
 +**wiederholungs-Knoten:**
 +  * links: Aussage innerhalb der Klammer
 +  * rechts: erste Anweisung innerhalb des while-Blocks (d.h. innerhalb der geschweiften Klammern)
 +  * naechsteAnweisung: Erste Anweisung, die der while-Anweisung folgt (d.h. erste Anweisung nach der schließenden geschweiften Klammer)
 +
 +**print-Knoten:**
 +  * links: Aussage, deren wert ausgegeben werden soll
 +  * rechts: ''null''
 +  * naechsteAnweisung: Die Anweisung, die auf die print-Anweisung folgt.
 +
 +**Zuweisungs-Knoten:**
 +  * links: text-Knoten, der den Bezeichner der Variablen enthält, der etwas zugewiesen werden soll.
 +  * rechts: Aussage, deren Wert der Variablen zugewiesen werden soll.
 +  * naechsteAnweisung: Die Anweisung, die auf die Zuweisung folgt.
 +
 +
 +
  
compilerbau/erweiterung/start.txt · Zuletzt geändert: 2021/12/29 11:29 von 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki