compilerbau:parser:start
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
compilerbau:parser:start [2021/10/28 20:43] – angelegt Martin Pabst | compilerbau:parser:start [2021/12/29 11:29] (aktuell) – Externe Bearbeitung 127.0.0.1 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
====== Parser ====== | ====== Parser ====== | ||
+ | <WRAP center round tip 60%> | ||
+ | Im folgenden findest Du die Beschreibung des Parsers. Den [[.test: | ||
+ | </ | ||
Der Parser analysiert die Liste der Tokens anhand einer gegebenen Syntax und erstellt eine Baumstruktur (" | Der Parser analysiert die Liste der Tokens anhand einer gegebenen Syntax und erstellt eine Baumstruktur (" | ||
Zeile 72: | Zeile 75: | ||
} | } | ||
</ | </ | ||
+ | Will man auf einen Baum im Programm zugreifen, so reicht es, seine Wurzel in einem Attribut zu speichern. Durch sukzessiven Aufruf von getRechts() und getLinks() bekommt man jeden beliebigen Knoten unterhalb. | ||
+ | |||
+ | ===== Die Klasse Parser ===== | ||
+ | Es gibt verschiedene Arten, einen Parser zu programmieren. Die einfachste, "von Hand" machbare Art ist ein [[http:// | ||
+ | * Eine Summe besteht aus | ||
+ | * einem Produkt/ | ||
+ | * **ausschließlich** aus einem Produkt/ | ||
+ | * Ein Produkt besteht aus | ||
+ | * einem " | ||
+ | * **ausschließlich** aus einem " | ||
+ | * Analog mit Differenz bzw. Quotient | ||
+ | * Ein " | ||
+ | * einer öffnenden Klammer, einer Summe(bzw. Differenz) und einer schließenden Klammer oder | ||
+ | * einem Minuszeichen gefolgt von einem " | ||
+ | * einer Variablen oder | ||
+ | * einer Zahl. | ||
+ | |||
+ | **Bem.:** In dieser Beschreibung steckt implizit schon drin, dass "Punkt vor Strich" | ||
+ | |||
+ | Obiger Beschreibung folgend ruft die Methode '' | ||
+ | Falls eine echte Summe vorliegt, kann diese natürlich wiederum der erste Summand einer weiteren Summe sein ('' | ||
+ | Die Methode '' | ||
+ | |||
+ | Insgesamt erkennt man am Vorgehen die Namensgebung: | ||
+ | |||
+ | Die Einzelheiten der Programmierung kann man am besten am kommentierten Sourcecode ersehen. | ||
+ | |||
+ | ===== Sourcecode ===== | ||
+ | <code java> | ||
+ | public class Parser { | ||
+ | |||
+ | /** | ||
+ | * Liste, die vom Lexer kommt | ||
+ | */ | ||
+ | private ArrayList< | ||
+ | |||
+ | /** | ||
+ | * Zur Speicherung des Parse-Baums (Abstract Syntax Tree) reicht es, die | ||
+ | * Wurzel zu speichern. Über sie bekommt man jeden beliebigen Knoten | ||
+ | * darunter. | ||
+ | */ | ||
+ | private Knoten wurzel; | ||
+ | |||
+ | /** | ||
+ | * Nummer des Tokens, das gerade analysiert wird (von 0 beginnend) | ||
+ | */ | ||
+ | private int position; | ||
+ | |||
+ | /** | ||
+ | * | ||
+ | * @param tokenListe | ||
+ | * Liste von Tokens, die geparst werden soll | ||
+ | */ | ||
+ | public Parser(ArrayList< | ||
+ | | ||
+ | this.tokenListe = tokenListe; | ||
+ | |||
+ | position = 0; | ||
+ | |||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Parst die dem Konstruktor übergebene Liste von Tokens und gibt einen | ||
+ | * Parse-Baum (Abstract Syntax Tree) zurück. | ||
+ | * | ||
+ | * @return Parse-Baum (Abstract Syntax Tree) | ||
+ | * | ||
+ | * Falls die Liste der Tokens nicht der Syntax entspricht | ||
+ | */ | ||
+ | public Knoten parse() { | ||
+ | |||
+ | wurzel = summeDifferenz(); | ||
+ | |||
+ | return wurzel; | ||
+ | |||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Versucht, eine Summe oder Differenz zu parsen. Parst zunächst den ersten | ||
+ | * Operanden (unter der Annahme, dass es eine Multiplikation oder Division | ||
+ | * ist) und sieht dann nach, ob ein Pluszeichen oder ein Minuszeichen kommt. | ||
+ | * Falls " | ||
+ | * Baum zusammen. | ||
+ | * | ||
+ | * Folgt ein weiteres Plus oder Minus, wird der Baum als erster Operand | ||
+ | * einer weiteren Summe/ | ||
+ | * dazu gesucht usw. | ||
+ | * | ||
+ | * Folgt kein weiteres Plus oder Minus, so endet die Methode und der | ||
+ | * aktuelle Baum wird zurückgegeben. | ||
+ | * | ||
+ | * @return Geparster Teilbaum | ||
+ | * | ||
+ | */ | ||
+ | private Knoten summeDifferenz() { | ||
+ | |||
+ | Knoten linkerOperand = produktQuotient(); | ||
+ | // | ||
+ | |||
+ | while(peek() == TokenType.plus || peek() == TokenType.minus) { | ||
+ | |||
+ | Token operator = nextToken(); | ||
+ | |||
+ | Knoten rechterOperand = produktQuotient(); | ||
+ | |||
+ | Knoten neuerKnoten = new Knoten(operator, | ||
+ | | ||
+ | |||
+ | linkerOperand = neuerKnoten; | ||
+ | |||
+ | } | ||
+ | |||
+ | return linkerOperand; | ||
+ | |||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Wie PlusMinus, jedoch für Mal und geteilt. Als erster bzw. zweiter | ||
+ | * Operand wird nach einem einfachen Term (Klammerterm, | ||
+ | * Negation) gesucht. | ||
+ | * | ||
+ | * @return | ||
+ | * | ||
+ | */ | ||
+ | private Knoten produktQuotient() { | ||
+ | |||
+ | Knoten linkerOperand = einfacherTerm(); | ||
+ | |||
+ | while(peek() == TokenType.mal || peek() == TokenType.geteilt) { | ||
+ | |||
+ | Token operator = nextToken(); | ||
+ | |||
+ | Knoten rechterOperand = einfacherTerm(); | ||
+ | |||
+ | Knoten neuerKnoten = new Knoten(operator, | ||
+ | | ||
+ | |||
+ | linkerOperand = neuerKnoten; | ||
+ | |||
+ | } | ||
+ | |||
+ | return linkerOperand; | ||
+ | |||
+ | } | ||
+ | |||
+ | private Knoten einfacherTerm() { | ||
+ | |||
+ | if(peek() == null) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | switch(peek()) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | // | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | // | ||
+ | | ||
+ | | ||
+ | | ||
+ | System.exit(0); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Gibt das nächste Token aus der Tokenliste zurück, erhöht aber nicht die | ||
+ | * Leseposition | ||
+ | * | ||
+ | * @return | ||
+ | */ | ||
+ | public TokenType peek() { | ||
+ | |||
+ | if(position < tokenListe.size()) { | ||
+ | |||
+ | return tokenListe.get(position).getTokenType(); | ||
+ | |||
+ | } | ||
+ | |||
+ | return null; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Gibt das nächste Token aus der Tokenliste zurück und erhöht(!) die | ||
+ | * Leseposition | ||
+ | * | ||
+ | * @return | ||
+ | */ | ||
+ | public Token nextToken() { | ||
+ | |||
+ | if(position < tokenListe.size()) { | ||
+ | |||
+ | Token token = tokenListe.get(position); | ||
+ | |||
+ | position++; | ||
+ | |||
+ | return token; | ||
+ | |||
+ | } | ||
+ | |||
+ | return null; | ||
+ | |||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Wirft eine Exception, wenn das nächste Token in der Tokenliste nicht dem | ||
+ | * übergebenen Typ entspricht. | ||
+ | * | ||
+ | * @param tokenType | ||
+ | * | ||
+ | */ | ||
+ | public void erwarte(TokenType tokenType) { | ||
+ | |||
+ | if(peek() == null) { | ||
+ | println( | ||
+ | | ||
+ | + tokenType); | ||
+ | | ||
+ | } | ||
+ | |||
+ | if(peek() != tokenType) { | ||
+ | println(" | ||
+ | | ||
+ | } | ||
+ | |||
+ | nextToken(); | ||
+ | |||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Nur zu Debuggingzwecken | ||
+ | */ | ||
+ | public String toString() { | ||
+ | |||
+ | return toString(wurzel, | ||
+ | | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Traversiert vom übergebenen Knoten ausgehend den Teilbaum in pre-order | ||
+ | * Reihenfolge, | ||
+ | * komplette linke Teilbaum, der dranhängt, dann der komplette rechte | ||
+ | * Teilbaum, der dranhängt. | ||
+ | * | ||
+ | * @param knoten | ||
+ | * @param einruecken | ||
+ | * @param sb | ||
+ | */ | ||
+ | private String toString(Knoten knoten, String einruecken) { | ||
+ | |||
+ | String sb = ""; | ||
+ | | ||
+ | sb += einruecken; | ||
+ | sb += knoten.getToken().toString() + " | ||
+ | |||
+ | if(knoten.getLinks() != null) { | ||
+ | sb += toString(knoten.getLinks(), | ||
+ | } | ||
+ | |||
+ | if(knoten.getRechts() != null) { | ||
+ | sb += toString(knoten.getRechts(), | ||
+ | } | ||
+ | |||
+ | return sb; | ||
+ | |||
+ | } | ||
+ | |||
+ | public Knoten getWurzel() { | ||
+ | return wurzel; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | |||
+ | [[..interpreter: | ||
compilerbau/parser/start.1635446596.txt.gz · Zuletzt geändert: 2021/12/29 11:29 (Externe Bearbeitung)