Ich arbeite an meinen Compilerkonzepten, bin aber etwas verwirrt ... Durch Googeln habe ich keine eindeutige Antwort erhalten.
Sind SLR- und LR (0) -Parser ein und dasselbe? Wenn nicht, was ist der Unterschied?
Ich arbeite an meinen Compilerkonzepten, bin aber etwas verwirrt ... Durch Googeln habe ich keine eindeutige Antwort erhalten.
Sind SLR- und LR (0) -Parser ein und dasselbe? Wenn nicht, was ist der Unterschied?
Antworten:
Sowohl LR (0) - als auch SLR (1) -Parser sind direktionale, prädiktive Bottom-up-Parser . Das bedeutet, dass
Sowohl LR (0) und SLR (1) Verschiebe / reduzieren Parsern Bedeutung haben , dass sie die Wertmarken des Eingangsstroms zu verarbeiten , indem sie auf einem Stapel platzieren, und an jedem Punkt entweder Verschieben eines Tokens , indem sie auf den Stapel geschoben oder reduzieren einige Folge von Terminals und Nicht-Terminals auf dem Stapel zurück zu einem Nicht-Terminal-Symbol. Es kann gezeigt werden, dass jede Grammatik mit einem Shift / Reduce-Parser von unten nach oben analysiert werden kann, dieser Parser jedoch möglicherweise nicht deterministisch ist . Das heißt, der Parser muss möglicherweise "raten", ob eine Verschiebung oder eine Reduzierung angewendet werden soll, und muss möglicherweise zurückverfolgen, um zu erkennen, dass er die falsche Wahl getroffen hat. Unabhängig davon, wie leistungsfähig ein von Ihnen erstellter deterministischer Verschiebungs- / Reduzierungsparser ist, kann er niemals alle Grammatiken analysieren.
Wenn ein deterministischer Verschiebungs- / Reduzierungsparser verwendet wird, um eine Grammatik zu analysieren, die er nicht verarbeiten kann, führt dies zu Verschiebungs- / Reduzierungskonflikten oder Reduzieren / Reduzieren von Konflikten , wobei der Parser in einen Zustand eintreten kann, in dem er nicht sagen kann, welche Aktion er ausführen soll. In einem Verschiebungs- / Reduzierungskonflikt kann nicht festgelegt werden, ob dem Stapel ein weiteres Symbol hinzugefügt oder die oberen Symbole des Stapels reduziert werden sollen. In einem Reduzierungs- / Reduzierungskonflikt weiß der Parser, dass er die oberen Symbole des Stapels durch ein Nicht-Terminal ersetzen muss, kann jedoch nicht sagen, welche Reduktion verwendet werden soll.
Ich entschuldige mich, wenn dies eine langwierige Darstellung ist, aber wir brauchen dies, um den Unterschied zwischen LR (0) und SLR (1) -Parsing angehen zu können. Ein LR (0) -Parser ist ein Shift / Reduce-Parser, der null Lookahead-Token verwendet, um zu bestimmen, welche Aktion ausgeführt werden soll (daher die 0). Dies bedeutet, dass der Parser in jeder Konfiguration des Parsers eine eindeutige Aktion auswählen muss - entweder er verschiebt ein bestimmtes Symbol oder wendet eine bestimmte Reduzierung an. Wenn zwei oder mehr Entscheidungen getroffen werden müssen, schlägt der Parser fehl und wir sagen, dass die Grammatik nicht LR (0) ist.
Denken Sie daran, dass die beiden möglichen LR-Konflikte Verschieben / Reduzieren und Reduzieren / Reduzieren sind. In beiden Fällen gibt es mindestens zwei Aktionen, die der LR (0) -Automat ausführen könnte, und er kann nicht sagen, welche von ihnen verwendet werden sollen. Da mindestens eine der widersprüchlichen Aktionen eine Reduzierung ist, besteht eine vernünftige Angriffslinie darin, zu versuchen, dass der Parser vorsichtiger ist, wenn er eine bestimmte Reduzierung durchführt. Nehmen wir genauer an, der Parser darf das nächste Eingabezeichen überprüfen, um zu bestimmen, ob er verschoben oder reduziert werden soll. Wenn wir dem Parser nur erlauben, zu reduzieren, wenn es "sinnvoll" ist (für eine Definition von "macht Sinn"), können wir den Konflikt möglicherweise beseitigen, indem der Automat speziell wählt, ob er in a entweder verschiebt oder reduziert besonderer Schritt.
In SLR (1) ("Simplified LR (1)") darf der Parser ein Lookahead-Token betrachten, wenn er entscheidet, ob es verschoben oder reduziert werden soll. Insbesondere wenn der Parser versuchen möchte, etwas von der Form A → w (für Nichtterminal A und Zeichenfolge w) zu reduzieren, betrachtet er das nächste Eingabe-Token. Wenn dieses Token in einer Ableitung legal nach dem nicht terminalen A erscheinen könnte, wird der Parser reduziert. Sonst nicht. Die Intuition hier ist, dass es in einigen Fällen keinen Sinn macht, eine Reduzierung zu versuchen, da es angesichts der bisher gesehenen Token und des bevorstehenden Tokens keine Möglichkeit gibt, dass die Reduzierung jemals korrekt sein könnte.
Der einzige Unterschied zwischen LR (0) und SLR (1) besteht in dieser zusätzlichen Fähigkeit, zu entscheiden, welche Maßnahmen bei Konflikten ergriffen werden sollen. Aus diesem Grund kann jede Grammatik, die von einem LR (0) -Parser analysiert werden kann, von einem SLR (1) -Parser analysiert werden. SLR (1) -Parser können jedoch eine größere Anzahl von Grammatiken analysieren als LR (0).
In der Praxis ist SLR (1) jedoch immer noch eine ziemlich schwache Analysemethode. Häufiger werden LALR (1) ("Lookahead LR (1)") Parser verwendet. Auch sie versuchen, Konflikte in einem LR (0) -Parser zu lösen, aber die Regeln, die sie zur Lösung von Konflikten verwenden, sind weitaus präziser als die in SLR (1) verwendeten, und folglich ist eine viel größere Anzahl von Grammatiken LALR (1). als SLR (1). Um etwas genauer zu sein, versuchen SLR (1) -Parser, Konflikte zu lösen, indem sie sich die Struktur der Grammatik ansehen, um mehr Informationen darüber zu erhalten, wann verschoben und wann reduziert werden muss. LALR (1) -Parser betrachten sowohl die Grammatik als auch den LR (0) -Parser, um noch genauere Informationen darüber zu erhalten, wann verschoben und wann reduziert werden muss. Da LALR (1) die Struktur des LR (0) -Parsers betrachten kann, kann es genauer identifizieren, wenn bestimmte Konflikte falsch sind.yacc
und bison
standardmäßig LALR (1) -Parser erzeugen.
In der Vergangenheit wurden LALR (1) -Parser normalerweise nach einer anderen Methode erstellt, die sich auf den weitaus leistungsstärkeren LR (1) -Parser stützte. Daher wird LALR (1) häufig so beschrieben. Um dies zu verstehen, müssen wir über LR (1) -Parser sprechen. In einem LR (0) -Parser verfolgt der Parser, wo er sich möglicherweise mitten in einer Produktion befindet. Sobald es festgestellt hat, dass es das Ende einer Produktion erreicht hat, weiß es zu versuchen, zu reduzieren. Der Parser kann jedoch möglicherweise nicht erkennen, ob er sich am Ende einer Produktion und in der Mitte einer anderen befindet, was zu einem Verschiebungs- / Reduzierungskonflikt führt, oder welche von zwei verschiedenen Produktionen er am Ende erreicht hat (eine Reduktion /). Konflikt reduzieren). In LR (0) führt dies sofort zu einem Konflikt und der Parser schlägt fehl. In SLR (1) oder LALR (1),
In einem LR (1) -Parser verfolgt der Parser während des Betriebs zusätzliche Informationen. Neben der Verfolgung der Produktion, von der der Parser glaubt, dass sie verwendet wird, wird auch verfolgt, welche möglichen Token nach Abschluss dieser Produktion erscheinen könnten. Da der Parser diese Informationen bei jedem Schritt verfolgt und nicht nur, wenn er die Entscheidung treffen muss, ist der LR (1) -Parser wesentlich leistungsfähiger und präziser als jeder LR (0), SLR (1) oder LALR (1) -Parser, über die wir bisher gesprochen haben. LR (1) ist eine äußerst leistungsfähige Analysetechnik, und mit kniffliger Mathematik kann gezeigt werden, dass jede Sprache, die durch einen Shift / Reduce-Parser deterministisch analysiert werden kann , eine Grammatik hat, die mit einem LR (1) -Automaten analysiert werden kann. (Beachten Sie, dass dies nicht alle Grammatiken bedeutetdas deterministisch analysiert werden kann, sind LR (1); Dies besagt nur, dass eine Sprache, die deterministisch analysiert werden könnte, eine gewisse LR (1) -Grammatik hat. Diese Leistung hat jedoch ihren Preis, und ein generierter LR (1) -Parser benötigt möglicherweise so viele Informationen, dass er in der Praxis möglicherweise nicht verwendet werden kann. Ein LR (1) -Parser für eine echte Programmiersprache benötigt beispielsweise möglicherweise mehrere zehn bis hundert Megabyte zusätzliche Informationen, um ordnungsgemäß zu funktionieren. Aus diesem Grund wird LR (1) in der Praxis normalerweise nicht verwendet, und stattdessen werden schwächere Parser wie LALR (1) oder SLR (1) verwendet.
In jüngerer Zeit hat ein neuer Parsing-Algorithmus namens GLR (0) ("Generalized LR (0)") an Popularität gewonnen. Anstatt zu versuchen, die Konflikte zu lösen, die in einem LR (0) -Parser auftreten, versucht der GLR (0) -Parser stattdessen, alle möglichen Optionen parallel zu testen. Mit einigen cleveren Tricks kann dies für viele Grammatiken sehr effizient ausgeführt werden. Darüber hinaus kann GLR (0) jede kontextfreie Grammatik überhaupt analysieren, selbst Grammatiken, die von einem LR (k) -Parser für kein k analysiert werden können. Andere Parser sind ebenfalls dazu in der Lage (z. B. der Earley-Parser oder ein CYK-Parser), obwohl GLR (0) in der Praxis tendenziell schneller ist.
Wenn Sie mehr erfahren möchten, habe ich in diesem Sommer einen Einführungskurs für Compiler unterrichtet und knapp zwei Wochen lang über Parsing-Techniken gesprochen. Wenn Sie eine genauere Einführung in LR (0), SLR (1) und eine Vielzahl anderer leistungsstarker Parsing-Techniken erhalten möchten, können Sie meine Vorlesungsfolien und Hausaufgaben zum Parsen genießen. Alle Kursmaterialien finden Sie hier auf meiner persönlichen Website .
Hoffe das hilft!
Das habe ich gelernt. Normalerweise kann der LR (0) -Parser mehrdeutig sein, dh ein Feld der Tabelle (das Sie zum Erstellen des Parsers ableiten) kann mehrere Werte haben (oder), um es besser auszudrücken: Der Parser führt zu zwei Endzuständen mit derselben Eingabe. Daher wird ein SLR-Parser erstellt, um diese Mehrdeutigkeit zu beseitigen. Um es zu konstruieren, finden Sie alle Produktionen, die zu goto-Zuständen führen, suchen Sie das Follow für das Produktionssymbol auf der linken Seite und schließen Sie nur die goto-Zustände ein, die im follow vorhanden sind. Dieser Inturn bedeutet, dass Sie keine Produktion einschließen, die mit dem Original-Grammatik nicht möglich ist (da dieser Status nicht im folgenden Satz enthalten ist)