Als ich anfing, Parser-Kombinatoren zu verwenden, war meine erste Reaktion ein Gefühl der Befreiung von einer künstlichen Unterscheidung zwischen Parsing und Lexing. Plötzlich wurde alles nur noch analysiert!
Vor kurzem bin ich jedoch auf dieses Posting auf codereview.stackexchange gestoßen, das jemanden veranschaulicht, der diese Unterscheidung wieder herstellt. Zuerst dachte ich, dass dies sehr albern von ihnen war, aber dann führt die Tatsache, dass Funktionen in Parsec existieren, um dieses Verhalten zu unterstützen, mich selbst in Frage zu stellen.
Welche Vor- und Nachteile hat das Parsen eines bereits lexierten Streams in Parser-Kombinatoren?
parsing
lexer
parser-combinator
Eli Frey
quelle
quelle
Antworten:
Unter Parsing verstehen wir am häufigsten die Analyse von kontextfreien Sprachen. Eine kontextfreie Sprache ist mächtiger als eine reguläre Sprache, daher kann der Parser (meistens) die Arbeit des lexikalischen Analysators sofort erledigen.
Dies ist jedoch a) ziemlich unnatürlich, b) oft ineffizient.
Für a), wenn ich daran denke , wie zum Beispiel ein
if
Ausdruck aussieht, denke ich , wenn expr DANN ausdr ELSE ausdr und nicht ‚i‘ ‚f‘, vielleicht ein paar Räume, dann ein beliebiges Zeichen ein Ausdruck mit beginnen, usw. Sie das bekommen Idee.Für b) gibt es leistungsstarke Tools, mit denen lexikalische Entitäten wie Bezeichner, Literale, Klammern aller Art usw. ausgezeichnet erkannt werden können. Sie erledigen ihre Arbeit praktisch im Handumdrehen und bieten Ihnen eine schöne Oberfläche: eine Liste von Token. Keine Sorge mehr, Leerzeichen im Parser zu überspringen. Ihr Parser wird viel abstrakter, wenn es um Token und nicht um Zeichen geht.
Wenn Sie der Meinung sind, dass ein Parser mit Low-Level-Dingen beschäftigt sein sollte, warum dann überhaupt Zeichen verarbeiten? Man könnte es auch auf der Ebene der Bits schreiben! Sie sehen, ein solcher Parser, der auf der Bit-Ebene arbeitet, wäre fast unverständlich. Das Gleiche gilt für Charaktere und Marken.
Nur meine 2 Cent.
quelle
if = string "if" >> expr >> string "then" >> expr >> string "else" >> expr
.Jeder, der vorschlägt, dass das Trennen von Lexing und Parsing eine "gute Praxis" ist - da muss ich widersprechen -, bietet in vielen Fällen mehr Leistung, und die Auswirkungen auf die Leistung sind nicht so schlimm, wie sie in der Tabelle dargestellt werden andere Antworten (siehe Packrat ).
Dieser Ansatz ist hervorragend geeignet, wenn mehrere verschiedene Sprachen in einem einzigen Eingabestream gemischt werden müssen. Dies wird nicht nur durch die seltsame metaprogramming orientierten Sprachen wie benötigt Katahdin und gleichermaßen , aber für viel mehr Mainstream - Anwendungen als auch, wie Literarische Programmierung (Misch Latex und, sagen wir, C ++), unter Verwendung von HTML in Kommentaren, Füllung Javascript in HTML, und bald.
quelle
Ein lexikalischer Analysator erkennt eine reguläre Sprache und ein Parser erkennt eine kontextfreie Sprache. Da jede reguläre Sprache auch kontextfrei ist (sie kann durch eine sogenannte rechtslineare Grammatik definiert werden ), kann ein Parser auch eine reguläre Sprache erkennen, und die Unterscheidung zwischen Parser und lexikalischem Analysator scheint eine unnötige Komplexität hinzuzufügen: einen einzelnen Kontext -freie Grammatik (Parser) könnte die Aufgabe eines Parsers und eines lexikalischen Analysators übernehmen.
Andererseits kann es nützlich sein, einige Elemente einer kontextfreien Sprache durch eine reguläre Sprache (und daher einen lexikalischen Analysator) zu erfassen, weil
Die Trennung von Parsing und lexikalischer Analyse bietet den Vorteil, dass Sie mit einer einfacheren kontextfreien Grammatik arbeiten und einige grundlegende (häufig routinemäßige) Aufgaben im lexikalischen Analysator (divide et impera) zusammenfassen können.
BEARBEITEN
Ich bin mit Parser-Kombinatoren nicht vertraut, daher bin ich mir nicht sicher, wie die obigen Überlegungen in diesem Zusammenhang gelten. Mein Eindruck ist, dass selbst wenn man mit Parser-Kombinatoren nur eine kontextfreie Grammatik hat, die Unterscheidung zwischen zwei Ebenen (lexikalische Analyse / Analyse) dazu beitragen könnte, diese Grammatik modularer zu gestalten. Wie bereits erwähnt, kann die untere Ebene für die lexikalische Analyse grundlegende wiederverwendbare Parser für Bezeichner, Literale usw. enthalten.
quelle
\alpha'_1 (K_0, \vec{T})
\ alpha'_1, K_0 und \ vec {T}. sind Bezeichner.Lexing und Parsing sollten einfach getrennt werden, da sie unterschiedliche Komplexitäten aufweisen. Lexing ist ein DFA (deterministischer endlicher Automat) und ein Parser ist ein PDA (Push-Down-Automat). Dies bedeutet, dass das Parsen von Natur aus mehr Ressourcen verbraucht als das Lexen, und dass nur DFAs bestimmte Optimierungstechniken zur Verfügung stehen. Darüber hinaus ist das Schreiben einer endlichen Zustandsmaschine viel weniger komplex und einfacher zu automatisieren.
Sie sind verschwenderisch, wenn Sie einen Analysealgorithmus zum Lexieren verwenden.
quelle
Einer der Hauptvorteile von Separate Parse / Lex ist die Zwischendarstellung - der Token-Stream. Dies kann auf verschiedene Arten verarbeitet werden, die mit einem kombinierten lex / parse sonst nicht möglich wären.
Das heißt, ich habe festgestellt, dass ein guter, rekursiver Menschenverstand weniger kompliziert und einfacher zu handhaben ist als das Erlernen eines Parsergenerators und ich muss herausfinden, wie man die Schwäche des Grammatikers innerhalb der Regeln des Parsergenerators ausdrückt.
quelle