36 lines
3.3 KiB
TeX
36 lines
3.3 KiB
TeX
|
\section{Lexer \& Parser}
|
||
|
\subsection{Lexer}
|
||
|
|
||
|
Der Lexer wurde mit dem Alex tool implementiert. Dieser ist dafür zuständig den langen String in einzelne Tokens umzuwandeln.
|
||
|
In der Alex Datei gibt es für jedes Token einen regulären Ausdruck. Bei den meisten Tokens ist das einfach das Schlüsselwort.
|
||
|
Etwas komplexer waren Identifier, Integerliterale Strings und Chars.
|
||
|
Für die Definition wurde sich eng an die offizielle Java Language Specification gehalten.
|
||
|
Es ist beispielsweise auch möglich Unterstriche in Integerliterale einzubauen (Bsp.: \texttt{234\_343\_000}).
|
||
|
Es sind fast alle Schlüsselwörter von Java im Lexer implementiert, auch wenn nicht alle davon vom Parser geparst werden können.
|
||
|
Whitespace und Kommentare werden direkt ignoriert und verworfen.
|
||
|
Für Charliterale und Integerliterale gibt es auch spezielle Fehlermeldungen. Die meisten Tokens haben nur die Information, zu welchem Keyword sie gehören.
|
||
|
Eine Ausnahme bilden der Identifier und die Literale. Für den Identifier wird noch der Name gespeichert und für die Literale der entsprechende Wert.
|
||
|
Mit der Funktion alexScanTokens kann dann ein beliebiger String in Tokens umgewandelt werden.
|
||
|
Die komplexeren Tokens haben Unittests, welche mit dem Testframework HUnit geschrieben wurden.
|
||
|
Es gibt Tests für Kommentare, Identifier, Literale und ein paar weitere Tokens.
|
||
|
|
||
|
\subsection{Parser}
|
||
|
|
||
|
Der Parser wurde mit dem Happy tool implementiert. Er baut aus einer Liste von Tokens einen ungetypten AST.
|
||
|
Wir haben bereits eine Grammatik bekommen und mussten diese noch in den AST umwandeln.
|
||
|
Um den Parser aufzubauen wurde zuerst ein Großteil der Grammatik auskommentiert und Stück für Stück wurden die Umwandlungen hinzugefügt.
|
||
|
Immer wenn ein neues Feature umgesetzt wurde, wurde dafür ein weiterer Unit Test geschrieben.
|
||
|
Es gibt also für jede komplexe Ableitungsregel mindestens einen Unittest. Als erstes wurden leere Methoden und Felder umgesetzt.
|
||
|
Da in Java Methoden und Felder durcheinander vorkommen können geben die Ableitungsregeln einen Datentype namens \texttt{MethodOrFieldDeclaration} zurück.
|
||
|
Über Pattern Matching baut die classbodydeclarations Regel dann eine Tupel mit einer Liste aus Methoden und einer aus Feldern.
|
||
|
Über pattern matching werden diese Listen dann erweitert und in der darüberliegenden Regel schließlich extrahiert.
|
||
|
Die Konstruktoren sind in diesem Fall auch normale Methoden mit dem Rückgabewert `void` und dem Namen \texttt{<init>}.
|
||
|
Auf diese Weise müssen sie nicht mehr vom Typcheck oder vom Bytecode verändert werden.
|
||
|
In Java ist es möglich mehrere Variablen in einer Zeile zu deklarieren (Bsp.: \texttt{int x, y;}).
|
||
|
Beim Parsen ergiebt sich dann die Schwierigkeit, dass man in dem Moment, wo man die Variable parst nicht weiß welchen Datentyp diese hat.
|
||
|
Aus diesem Grund gibt es den Datentyp Declarator, welcher nur den Identifier und eventuell eine Zuweisung enthält.
|
||
|
In den darüberliegenden Regeln fielddeclaration und localvariabledeclaration wird dann die Typinformation hinzugefügt mithilfe der Funktion convertDeclarator.
|
||
|
Für die Zuweisung wird auch die Kombination mit Rechenoperatoren unterstützt. Das Ganze ist als syntactic sugar im Parser umgesetzt.
|
||
|
Wenn es einen Zuweisungsoperator gibt, dann wird der Ausdruck in eine Zuweisung und Rechnung aufgeteilt.
|
||
|
Bsp.: \texttt{x += 3;} wird umgewandelt zu \texttt{x = x + 3}.
|