Ich schreibe einen Parser für eine von mir erstellte Auszeichnungssprache (in Python schreiben, aber das ist für diese Frage nicht wirklich relevant - in der Tat, wenn dies wie eine schlechte Idee erscheint, würde ich einen Vorschlag für einen besseren Pfad lieben). .
Ich lese hier über Parser: http://www.ferg.org/parsing/index.html , und ich arbeite daran, den Lexer zu schreiben, der, wenn ich das richtig verstehe, den Inhalt in Token aufteilen soll. Ich habe Probleme zu verstehen, welche Tokentypen ich verwenden sollte oder wie ich sie erstelle. Die Tokentypen in dem Beispiel, mit dem ich verknüpft habe, sind beispielsweise:
- STRING
- IDENTIFIERER
- NUMMER
- WHITESPACE
- KOMMENTAR
- EOF
- Viele Symbole wie {und (zählen als eigener Tokentyp
Das Problem, das ich habe, ist, dass die allgemeineren Tokentypen für mich ein bisschen willkürlich erscheinen. Warum hat STRING beispielsweise einen eigenen Token-Typ im Vergleich zu IDENTIFIER? Eine Zeichenfolge könnte als STRING_START + (IDENTIFIER | WHITESPACE) + STRING_START dargestellt werden.
Dies mag auch mit den Schwierigkeiten meiner Sprache zu tun haben. Beispielsweise werden Variablendeklarationen so geschrieben {var-name var value}
und mit bereitgestellt {var-name}
. Es scheint '{'
und '}'
sollte sich um eigene Token handeln, aber sind die Token-Typen VAR_NAME und VAR_VALUE zulässig, oder würden beide unter IDENTIFIER fallen? Außerdem kann der VAR_VALUE tatsächlich Leerzeichen enthalten. Das Leerzeichen nach var-name
wird verwendet, um den Beginn des Werts in der Deklaration zu kennzeichnen. Jedes andere Leerzeichen ist Teil des Werts. Wird dieses Leerzeichen zu einem eigenen Token? Whitespace hat in diesem Zusammenhang nur diese Bedeutung. Außerdem {
kann es sein , dass keine Variablendeklaration beginnt. Dies hängt vom Kontext ab (es gibt wieder dieses Wort!). {:
startet eine Namensdeklaration und{
kann sogar als Teil eines Wertes verwendet werden.
Meine Sprache ähnelt Python, da Blöcke mit Einrückungen erstellt werden. Ich lese darüber , wie Python verwendet die Lexer SPIEGELSTRICH und Dedent Token (die mehr oder weniger als das, was dazu dienen , zu schaffen {
und }
in vielen anderen Sprachen tun würde). Python behauptet, kontextfrei zu sein, was für mich bedeutet, dass es zumindest dem Lexer egal sein sollte, wo es sich im Stream befindet, während er Token erstellt. Woher weiß Pythons Lexer, dass ein INDENT-Token mit einer bestimmten Länge erstellt wird, ohne die vorherigen Zeichen zu kennen (z. B. dass die vorherige Zeile eine neue Zeile war, erstellen Sie also die Leerzeichen für INDENT)? Ich frage, weil ich das auch wissen muss.
Meine letzte Frage ist die dümmste: Warum ist überhaupt ein Lexer notwendig? Es scheint mir, dass der Parser Zeichen für Zeichen gehen und herausfinden könnte, wo es ist und was es erwartet. Fügt der Lexer den Vorteil der Einfachheit hinzu?