Um die gestellte Frage zu beantworten (ohne übermäßig zu wiederholen, was in anderen Antworten erscheint)
Lexer und Parser sind nicht sehr unterschiedlich, wie aus der akzeptierten Antwort hervorgeht. Beide basieren auf einfachen Sprachformalismen: reguläre Sprachen für Lexer und fast immer kontextfreie (CF) Sprachen für Parser. Sie sind beide mit ziemlich einfachen Rechenmodellen verbunden, dem Finite-State-Automaten und dem Push-Down-Stack-Automaten. Reguläre Sprachen sind ein Sonderfall kontextfreier Sprachen, so dass Lexer mit der etwas komplexeren CF-Technologie hergestellt werden können. Aber es ist aus mindestens zwei Gründen keine gute Idee .
Ein grundlegender Punkt bei der Programmierung ist, dass eine Systemkomponente mit der am besten geeigneten Technologie ausgestattet werden sollte, damit sie leicht zu produzieren, zu verstehen und zu warten ist. Die Technologie sollte nicht übertrieben sein (unter Verwendung von Techniken, die viel komplexer und kostspieliger sind als erforderlich), und sie sollte auch nicht an der Grenze ihrer Leistungsfähigkeit stehen, sodass technische Verzerrungen erforderlich sind, um das gewünschte Ziel zu erreichen.
Deshalb "scheint es in Mode zu sein, reguläre Ausdrücke zu hassen". Obwohl sie viel können, benötigen sie manchmal eine sehr unlesbare Codierung, um dies zu erreichen, ganz zu schweigen von der Tatsache, dass verschiedene Erweiterungen und Einschränkungen bei der Implementierung ihre theoretische Einfachheit etwas verringern. Lexer tun dies normalerweise nicht und sind normalerweise eine einfache, effiziente und geeignete Technologie zum Parsen von Token. Die Verwendung von CF-Parsern für Token wäre übertrieben, obwohl dies möglich ist.
Ein weiterer Grund, den CF-Formalismus nicht für Lexer zu verwenden, besteht darin, dass es möglicherweise verlockend ist, die volle CF-Leistung zu nutzen. Dies könnte jedoch zu strukturellen Problemen beim Lesen von Programmen führen.
Grundsätzlich ist der größte Teil der Struktur des Programmtextes, aus dem die Bedeutung extrahiert wird, eine Baumstruktur. Es drückt aus, wie der Analysesatz (Programm) aus Syntaxregeln generiert wird. Die Semantik wird durch Kompositionstechniken (Homomorphismus für mathematisch orientierte) aus der Art und Weise abgeleitet, wie Syntaxregeln zum Erstellen des Analysebaums erstellt werden. Daher ist die Baumstruktur wesentlich. Die Tatsache, dass Token mit einem regulären lexer auf Set-Basis identifiziert werden, ändert nichts an der Situation, da CF, das mit Regular zusammengesetzt ist, immer noch CF ergibt (ich spreche sehr locker von regulären Wandlern, die einen Zeichenstrom in einen Tokenstrom verwandeln).
Mit CF zusammengesetzte CF (über CF-Wandler ... Entschuldigung für die Mathematik) geben jedoch nicht unbedingt CF und machen die Dinge möglicherweise allgemeiner, aber in der Praxis weniger nachvollziehbar. Daher ist CF nicht das geeignete Werkzeug für Lexer, obwohl es verwendet werden kann.
Einer der Hauptunterschiede zwischen regulären und CF-Sprachen besteht darin, dass reguläre Sprachen (und Wandler) mit fast jedem Formalismus auf verschiedene Weise sehr gut zusammensetzen, während CF-Sprachen (und Wandler) dies nicht tun, nicht einmal mit sich selbst (mit wenigen Ausnahmen).
(Beachten Sie, dass normale Wandler möglicherweise andere Verwendungszwecke haben, z. B. die Formalisierung einiger Techniken zur Behandlung von Syntaxfehlern.)
BNF ist nur eine spezielle Syntax für die Darstellung von CF-Grammatiken.
EBNF ist ein syntaktischer Zucker für BNF , der die Möglichkeiten der regulären Notation nutzt, um eine genauere Version der BNF-Grammatiken zu erhalten. Es kann immer in ein äquivalentes reines BNF umgewandelt werden.
Die reguläre Notation wird in EBNF jedoch häufig nur verwendet, um diese Teile der Syntax hervorzuheben, die der Struktur lexikalischer Elemente entsprechen und mit dem Lexer erkannt werden sollten, während der Rest eher in reinem BNF dargestellt wird. Aber es ist keine absolute Regel.
Zusammenfassend lässt sich sagen, dass die einfachere Struktur von Token mit der einfacheren Technologie regulärer Sprachen besser analysiert werden kann, während die baumorientierte Struktur der Sprache (der Programmsyntax) von CF-Grammatiken besser behandelt wird.
Ich würde vorschlagen, auch die Antwort von AHR zu lesen .
Dies lässt jedoch eine Frage offen: Warum Bäume?
Bäume sind eine gute Grundlage für die Angabe der Syntax, weil
Sie geben dem Text eine einfache Struktur
Es ist sehr praktisch, die Semantik auf der Grundlage dieser Struktur mit dem Text zu verknüpfen, und zwar mit einer mathematisch gut verstandenen Technologie (Komposition über Homomorphismen), wie oben angegeben. Es ist ein grundlegendes algebraisches Werkzeug, um die Semantik mathematischer Formalismen zu definieren.
Daher ist es eine gute Zwischendarstellung, wie der Erfolg von Abstract Syntax Trees (AST) zeigt. Beachten Sie, dass sich AST häufig vom Analysebaum unterscheidet, da die von vielen Fachleuten (z. B. LL oder LR) verwendete Analysetechnologie nur für eine Teilmenge von CF-Grammatiken gilt, wodurch grammatikalische Verzerrungen erzwungen werden, die später in AST korrigiert werden. Dies kann mit einer allgemeineren Parsing-Technologie (basierend auf dynamischer Programmierung) vermieden werden, die jede CF-Grammatik akzeptiert.
Aussagen über die Tatsache, dass Programmiersprachen eher kontextsensitiv (CF) als CF sind, sind willkürlich und umstritten.
Das Problem ist, dass die Trennung von Syntax und Semantik willkürlich ist. Das Überprüfen von Deklarationen oder Typübereinstimmungen kann entweder als Teil der Syntax oder als Teil der Semantik angesehen werden. Gleiches gilt für die Übereinstimmung von Geschlecht und Anzahl in natürlichen Sprachen. Es gibt jedoch natürliche Sprachen, in denen die Pluralübereinstimmung von der tatsächlichen semantischen Bedeutung von Wörtern abhängt, so dass sie nicht gut zur Syntax passt.
Viele Definitionen von Programmiersprachen in der Denotationssemantik setzen Deklarationen und Typprüfungen in die Semantik. Die Aussage von Ira Baxter, dass CF-Parser gehackt werden, um eine von der Syntax geforderte Kontextsensitivität zu erhalten, ist bestenfalls eine willkürliche Sicht auf die Situation. Es kann in einigen Compilern als Hack organisiert sein, muss es aber nicht sein.
Es ist auch nicht nur so, dass CS-Parser (in dem Sinne, wie sie in anderen Antworten hier verwendet werden) schwer zu erstellen und weniger effizient sind. Sie sind auch nicht ausreichend, um die Kinf der Kontextsensitivität, die erforderlich sein könnte, klar auszudrücken. Und sie erzeugen natürlich keine syntaktische Struktur (wie z. B. Analysebäume), die geeignet ist, die Semantik des Programms abzuleiten, dh den kompilierten Code zu generieren.