SLR-, LALR- und LR-Parser können alle mit derselben tabellengesteuerten Maschine implementiert werden.
Grundsätzlich sammelt der Parsing-Algorithmus, um die nächste Eingabe-Token T, und berät den aktuellen Zustand S (und die damit verbundene Look-Ahead, GOTO und Reduktion Tabellen) zu entscheiden, was zu tun ist:
- SHIFT: Wenn der Strom Die Tabelle sagt zu SHIFT auf dem Token T, das Paar (S, T) wird auf den Parse-Stapel geschoben, der Zustand wird entsprechend der GOTO-Tabelle für das aktuelle Token (z. B. GOTO (T)) geändert, ein weiteres Eingabetoken T 'wird abgerufen, und der Prozess wird wiederholt
- REDUZIEREN: Jeder Zustand hat 0, 1 oder viele mögliche Reduzierungen, die in diesem Zustand auftreten können. Wenn der Parser LR oder LALR ist, wird das Token mit Lookahead-Sätzen für alle gültigen Reduzierungen für den Status verglichen. Wenn das Token mit einem Lookahead-Set für eine Reduktion für die Grammatikregel G = R1 R2 .. Rn übereinstimmt, tritt eine Stapelreduktion und -verschiebung auf: die semantische Aktion für G wird aufgerufen, der Stapel wird n (von Rn) gepoppt, das Paar (S, G) wird auf den Stapel geschoben, der neue Zustand S 'wird auf GOTO (G) gesetzt, und der Zyklus wiederholt sich mit dem gleichen Token T. Wenn der Parser ein SLR - Parser ist, gibt es höchstens eine Reduktionsregel für den Zustand und so die Reduktion Aktion kann blind getan werden, ohne zu sehen, welche Reduktion gilt. Es ist nützlich für einen SLR-Parser zu wissen, ob eine Reduzierung ist oder nicht; Dies ist leicht zu sagen, wenn jeder Zustand die Anzahl der damit verbundenen Reduktionen explizit aufzeichnet, und diese Zählung wird für die L (AL) R-Versionen in der Praxis sowieso benötigt.
- FEHLER: Wenn weder SHIFT noch REDUCE möglich ist, wird ein Syntaxfehler gemeldet.
Also, wenn sie alle die gleiche Maschine verwenden, was ist der Punkt?
Der angebliche Wert in SLR ist seine Einfachheit in der Implementierung; Sie müssen nicht durch die möglichen Look-Ahead-Sets für die Reduktionsüberprüfung scannen, weil es höchstens eins gibt, und dies ist die einzige praktikable Aktion, wenn es keine SHIFT-Exits vom Status gibt. Welche Reduktion gilt, kann spezifisch an den Zustand angehängt werden, so dass die SLR-Parsing-Maschine nicht danach suchen muss. In der Praxis handhaben L (AL) R-Parser einen nützlichen größeren Satz von Sprachen, und es ist so wenig zusätzliche Arbeit zu implementieren, dass niemand SLR implementiert, außer als eine akademische Übung.
Der Unterschied zwischen LALR und LR hat mit der Tabelle Generator zu tun. LR-Parser-Generatoren verfolgen alle möglichen Reduktionen von bestimmten Zuständen und ihrer präzisen Lookahead-Menge; Sie enden mit Zuständen, in denen jede Verkleinerung mit ihrer genauen Lookahead-Menge aus ihrem linken Kontext verknüpft ist. Dies neigt dazu, ziemlich große Mengen von Zuständen zu bilden. LALR-Parsergeneratoren sind bereit, Zustände zu kombinieren, wenn die GOTO-Tabellen und Lookhead-Sets für Reduktionen kompatibel sind und nicht in Konflikt stehen; dies führt zu einer wesentlich geringeren Anzahl von Zuständen, zu dem Preis, dass bestimmte von LR zu unterscheidende Symbolsequenzen nicht unterschieden werden können. Also können LR-Parser eine größere Anzahl von Sprachen als LALR-Parser analysieren, haben aber sehr viel größere Parser-Tabellen. In der Praxis kann man LALR-Grammatiken finden, die nahe genug an den Zielsprachen liegen, dass die Größe der Zustandsmaschine optimiert werden muss; Die Stellen, an denen der LR-Parser besser wäre, werden durch Ad-hoc-Überprüfung außerhalb des Parsers behandelt.
Also: Alle drei benutzen die gleiche Maschine. SLR ist "einfach" in dem Sinne, dass Sie ein winziges bisschen der Maschinerie ignorieren können, aber es ist einfach nicht die Mühe wert. LR analysiert eine größere Anzahl von Sprachen, aber die Zustandstabellen sind in der Regel ziemlich groß. Damit bleibt LALR die praktische Wahl.
all dies gesagt ist, lohnt es sich zu wissen, dass GLR parsers freie Sprache jeden Kontext analysieren kann, kompliziertere Maschinen aber genau die gleichen Tabellen (einschließlich der kleineren Version von LALR verwendet wird) verwendet wird. Dies bedeutet, dass GLR strikter ist als LR, LALR und SLR; ziemlich viel, wenn Sie eine Standard-BNF-Grammatik schreiben können, wird GLR entsprechend analysieren. Der Unterschied in der Maschinerie ist, dass GLR bereit ist, mehrere Analysen zu versuchen, wenn es Konflikte zwischen der GOTO-Tabelle und den Lookahead-Sätzen gibt. (Wie GLR dies effizient ist, ist schier genial [nicht meins], aber passt nicht in diese SO Post).
Das ist für mich eine enorm nützliche Tatsache. Ich baue Programmanalysatoren und Codetransformatoren und Parser sind notwendig, aber "uninteressant"; Die interessante Arbeit ist, was Sie mit dem geparsten Ergebnis tun, und so liegt der Schwerpunkt auf der Post-Parsing-Arbeit. Die Verwendung von GLR bedeutet, dass ich relativ einfach Arbeitsgrammatiken erstellen kann, verglichen mit dem Hacken einer Grammatik, um in LALR verwendbare Form zu gelangen. Das ist sehr wichtig, wenn man versucht, nicht-akademische Sprachen wie C++ oder Fortran zu bearbeiten, wo man buchstäblich Tausende von Regeln braucht, um die gesamte Sprache gut zu handhaben, und man nicht sein Leben damit verbringen will, die Grammatikregeln zu hacken die Beschränkungen von LALR (oder sogar LR) erfüllen.
Als eine Art berühmtes Beispiel, C++ gilt als extrem schwierig zu parsen ... von Jungs tun LALR Parsing. C++ ist einfach zu analysieren mit GLR-Maschinen mit ziemlich genau die Regeln in der Rückseite des C++ Referenzhandbuchs zur Verfügung gestellt. (Ich habe genau einen solchen Parser, und er behandelt nicht nur Vanille C++, sondern auch eine Vielzahl von Herstellerdialekten. Dies ist nur in der Praxis möglich, weil wir einen GLR-Parser, IMHO, verwenden).
[EDIT November 2011: Wir haben unseren Parser erweitert, um alle C++ 11 zu behandeln. GLR hat das viel einfacher gemacht.]
Nun, auch ich bin auf der Suche nach einer richtigen Antwort auf diese, LALR (1) ist nur eine geringfügige Änderung von LR (1), wo die Tabellengröße reduziert wird, so dass wir die Speichernutzung minimieren können ... – vikkyhacks