compilerbau:erweiterung:start
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende ÜberarbeitungNächste ÜberarbeitungBeide Seiten der Revision | ||
compilerbau:erweiterung:start [2021/10/28 21:12] – [Erweiterung der Grammatik] Martin Pabst | compilerbau:erweiterung:start [2021/10/28 21:23] – [Erweiterung des Lexers] Martin Pabst | ||
---|---|---|---|
Zeile 41: | Zeile 41: | ||
</ | </ | ||
+ | |||
+ | ===== 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, | ||
+ | whileKeyword, | ||
+ | kleiner, groesser, identisch, kleinergleich, | ||
+ | zuweisung, | ||
+ | trueKeyword, | ||
+ | strichpunkt, | ||
+ | |||
+ | /** | ||
+ | * Nur als Knotentyp für Knoten des Syntaxbaums: | ||
+ | */ | ||
+ | negation | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Erweiterung des Lexers ===== | ||
+ | Damit der Lexer die Schlüsselwörter '' | ||
+ | |||
+ | <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) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | |||
+ | Etwas trickreicher sind die neuen Zeichen. Um etwa ''<'' | ||
+ | |||
+ | <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; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Damit sieht die Erkennung von ''>'', | ||
+ | |||
+ | <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(" | ||
+ | System.exit(1); | ||
+ | } | ||
+ | break; | ||
+ | </ | ||
+ | |||
+ | |||
+ | ===== Test des Lexers ===== | ||
+ | Der Lexer lässt sich wieder mit der Klasse '' | ||
+ | < | ||
+ | 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 | ||
+ | </ | ||
+ | |||
+ | |||
+ | ===== Erweiterung der Klasse Knoten ===== | ||
+ | Auch Anweisungen (Wiederholung, | ||
+ | |||
+ | <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; | ||
+ | |||
+ | |||
+ | ... | ||
+ | </ | ||
+ | |||
+ | 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: | ||
+ | |||
+ | **print-Knoten: | ||
+ | * links: Aussage, deren wert ausgegeben werden soll | ||
+ | * rechts: '' | ||
+ | * naechsteAnweisung: | ||
+ | |||
+ | **Zuweisungs-Knoten: | ||
+ | * links: text-Knoten, | ||
+ | * rechts: Aussage, deren Wert der Variablen zugewiesen werden soll. | ||
+ | * naechsteAnweisung: | ||
+ | |||
+ | |||
+ | |||
compilerbau/erweiterung/start.txt · Zuletzt geändert: 2021/12/29 11:29 von 127.0.0.1