compilerbau:lexer:start
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
compilerbau:lexer:start [2021/10/28 20:12] – [Die Klasse TokenType] Martin Pabst | compilerbau:lexer:start [2021/12/29 11:29] (aktuell) – Externe Bearbeitung 127.0.0.1 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
====== Lexer ====== | ====== Lexer ====== | ||
+ | |||
+ | <WRAP center round tip 60%> | ||
+ | Im folgenden findest Du die Beschreibung des Lexers. Den [[.test: | ||
+ | </ | ||
+ | |||
Der Lexer liest den Programmtext Zeichen für Zeichen und fasst diese zu kleinsten syntaktischen Einheiten, sogenannten Tokens, zusammen. Unsere Beispielsprache besteht aus folgenden 8 Tokens: | Der Lexer liest den Programmtext Zeichen für Zeichen und fasst diese zu kleinsten syntaktischen Einheiten, sogenannten Tokens, zusammen. Unsere Beispielsprache besteht aus folgenden 8 Tokens: | ||
Zeile 101: | Zeile 106: | ||
} | } | ||
</ | </ | ||
+ | |||
+ | |||
+ | ===== Funktionsweise des Lexers ===== | ||
+ | Die Klasse Lexer bekommt im Konstruktor den Programmtext übergeben und speichert ihn im Attribut '' | ||
+ | |||
+ | <code java> | ||
+ | public class Lexer { | ||
+ | |||
+ | /** | ||
+ | * Die Zeichenkette wird von links nach rechts abgearbeitet. Hier ist | ||
+ | * gespeichert, | ||
+ | */ | ||
+ | private int position; | ||
+ | |||
+ | /** | ||
+ | * Liste zur Speicherung der ermittelten Tokens | ||
+ | */ | ||
+ | private ArrayList< | ||
+ | |||
+ | /** | ||
+ | * Wir speichern den Programmtext in einem Attribut der Klasse, damit er | ||
+ | * nachher nicht von Methode zu Methode weitergereicht werden muss. | ||
+ | */ | ||
+ | private String text; | ||
+ | |||
+ | /** | ||
+ | * | ||
+ | * @param text | ||
+ | * Programmtext, | ||
+ | */ | ||
+ | public Lexer(String text) { | ||
+ | |||
+ | this.text = text; | ||
+ | |||
+ | position = 0; // Wir beginnen mit dem Zeichen ganz links | ||
+ | |||
+ | tokenListe = new ArrayList< | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | |||
+ | Die Methode '' | ||
+ | |||
+ | <code java> | ||
+ | /** | ||
+ | * Zerlegt den Programmtext, | ||
+ | * | ||
+ | * @return Liste mit Tokens | ||
+ | * @throws Exception | ||
+ | * Eine Exception wird ausgelöst, wenn der Programmtext Passagen | ||
+ | * | ||
+ | */ | ||
+ | public ArrayList< | ||
+ | |||
+ | /** | ||
+ | * Wiederholung, | ||
+ | */ | ||
+ | while(position < text.length()) { | ||
+ | |||
+ | /** | ||
+ | * peek() liest das nächste Zeichen im Programmtext, | ||
+ | * Variable position aber nicht. Ruft man peek() mehrmals | ||
+ | * hintereinander auf, liefert es also immer dasselbe Zeichen. | ||
+ | */ | ||
+ | char c = peek(); | ||
+ | |||
+ | if(istZiffer(c)) { | ||
+ | lexZahl(); | ||
+ | } else if(istBuchstabe(c)) { | ||
+ | lexText(); | ||
+ | } else { | ||
+ | switch(c) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | // Leerzeichen werden einfach überlesen | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | System.exit(0); | ||
+ | } | ||
+ | |||
+ | position++; | ||
+ | // verarbeitet, | ||
+ | |||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | return tokenListe; | ||
+ | |||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | ===== Die Hilfsmethoden lexZahl() und lexText() ===== | ||
+ | <code java> | ||
+ | /** | ||
+ | * Die Methode lexText geht davon aus, dass das nächste zu verarbeitende | ||
+ | * Zeichen ein Buchstabe ist. Solange weitere Buchstaben oder Ziffern | ||
+ | * kommen, liest sie sie und setzt sie zu einem Variablennamen zusammen. | ||
+ | */ | ||
+ | private void lexText() { | ||
+ | |||
+ | String variablenBezeichner = ""; | ||
+ | |||
+ | do { | ||
+ | char c = peek(); | ||
+ | variablenBezeichner += c; | ||
+ | position++; | ||
+ | } while(Character.isLetter(peek()) || Character.isDigit(peek()) || peek() == ' | ||
+ | |||
+ | tokenListe.add(new Token(variablenBezeichner)); | ||
+ | |||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Die Methode lexZahl liest eine Zahl | ||
+ | */ | ||
+ | private void lexZahl() { | ||
+ | |||
+ | String zahlAlsString = ""; | ||
+ | |||
+ | do { | ||
+ | char c = peek(); | ||
+ | zahlAlsString += c; | ||
+ | position++; | ||
+ | } while(Character.isDigit(peek()) || peek() == ' | ||
+ | |||
+ | /** | ||
+ | * Hier machen wir es uns leicht und lassen Java den String in eine Zahl | ||
+ | * konvertieren. Die Methode parseDouble ist für sich genommen natürlich | ||
+ | * auch ein Lexer. | ||
+ | */ | ||
+ | double zahl = Double.parseDouble(zahlAlsString); | ||
+ | |||
+ | tokenListe.add(new Token(zahl)); | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | Zum einfachen Hinzufügen eines Tokens, das weder eine Zahl noch Text darstellt, wird eine kleine Hilfsmethode definiert: | ||
+ | <code java> | ||
+ | /** | ||
+ | * Fügt der tokenListe das übergebene Token hinzu | ||
+ | * | ||
+ | * @param tokenType | ||
+ | */ | ||
+ | private void addToken(TokenType tokenType) { | ||
+ | tokenListe.add(new Token(tokenType)); | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | Der Zugriff auf den Programmtext geschieht immer über die Methode peek(), damit weniger Fehler beim Programmieren passieren: | ||
+ | <code java> | ||
+ | /** | ||
+ | * peek() liest das nächste Zeichen im Programmtext, | ||
+ | * position aber nicht. Ruft man peek() mehrmals hintereinander auf, liefert | ||
+ | * es also immer dasselbe Zeichen. | ||
+ | | ||
+ | * @return nächstes Zeichen im Programmtext | ||
+ | */ | ||
+ | private char peek() { | ||
+ | | ||
+ | return text.charAt(position); | ||
+ | } else { | ||
+ | return 0x; | ||
+ | } | ||
+ | } | ||
+ | </code java> | ||
+ | |||
+ | Die restlichen Methoden erklären sich von selbst: | ||
+ | <code java> | ||
+ | /** | ||
+ | * Vorsicht: Die übergebene Liste ist nur dann gefüllt, wenn zuvor die | ||
+ | * Methode lex aufgerufen wurde. | ||
+ | | ||
+ | * @return Liste mit den Tokens, in die der Lexer den Programmtext zerlegt | ||
+ | | ||
+ | */ | ||
+ | public ArrayList< | ||
+ | return tokenListe; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Nur zu Debuggingzwecken | ||
+ | */ | ||
+ | public String toString() { | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | s += token.toString() + " "; | ||
+ | } | ||
+ | |||
+ | | ||
+ | s = s.substring(0, | ||
+ | } | ||
+ | |||
+ | | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | |||
+ | [[..: | ||
compilerbau/lexer/start.1635444749.txt.gz · Zuletzt geändert: 2021/12/29 11:29 (Externe Bearbeitung)