LR(k)-Parser. CYK-Algorithmus ist zu langsam

LR(k)-Parser Ziele: • Effizienter (und deterministischer) Test, ob ein gegebenes Wort w in der Sprache L(G) enthalten ist. • Falls ja: Konstruktion de...
Author: Sven Langenberg
16 downloads 0 Views 52KB Size
LR(k)-Parser Ziele: • Effizienter (und deterministischer) Test, ob ein gegebenes Wort w in der Sprache L(G) enthalten ist. • Falls ja: Konstruktion des Syntaxbaums • Falls nein: Hinweise zum Fehler CYK-Algorithmus ist zu langsam.

596

LR(k)-Parser Bedeutung der Abkürzung: L: left-to-right scan R: rightmost derivation — Berechnung einer Rechtsableitung  Der Syntaxbaum wird bottom-up aufgebaut. k: Lookahead von k Zeichen — Der Algorithmus muss anhand der nächsten k Zeichen der Eingabe entscheiden, welche Ableitungsregel anzuwenden ist. 597

Notation α  β, falls β aus α mit einer Rechtsableitung in einem Schritt herleitbar ist. r

r * α  β, falls β aus α mit einer endlichen Folge

von Rechtsableitungen herleitbar ist.

598

Beispiel: L={aibicjdjekfk | i,j,k≥0} S8

• Links-Rechts-Scan erzeugt Num. der Regeln in bottom-upZ X3 7 5Y Ordnung (Postorder) • Anwendung der Regeln gemäß der a X b c Yd e Zf 2 6 4 umgedrehten Nummerierung ist a X b ε Rechtsableitung. ε 1 • Lookahead nötig. ε

599

Bemerkungen • Alternative Sichtweise: Syntaxanalyse entspricht „Reduzierung“ der Eingabe auf das Startsymbol durch umgekehrtes Anwenden der Regeln der Grammatik. • Syntaxanalyse mit Hilfe von Lookahead ist nur für spezielle Grammatiken möglich  siehe folgende Beispiele.

600

Beispiel T8.2.6 Grammatik G1 für a*c+a*d: SC, SD, CaC, Cc, DaD,Dd S

S

C

D

a

C

a

D

a

C

a

D

c

d

Lookahead von 0 ausreichend 601

Beispiel T8.2.7 Grammatik G2 für a*c+a*d: SCc, SDd, CCa, Cε, DDa, Dε S S C c

D d

C a

D a

C a

D a

C a

D a

ε

ε

Syntaxanalyse mit endlichem Lookahead nicht möglich. 602

Beispiel T.8.2.8 Grammatik für {aabbb,aabba}: SCD, Ca, DEF, DaG, Eab, Fbb,Gbba. S S C a

D E

C F

a b b b

a

D a G b b a

Lookahead von 2 nötig. 603

Definition von LR(k)-Grammatiken Ziel: Ein Lookahead von k soll ausreichen, um entscheiden zu können, welche Regel angewendet werden muss. Definition: FIRSTk(w1…wn):=

w1…wk, falls n≥k, w1…wn, sonst. 604

Neues Startsymbol S´ Ziel: Wir wollen einfach das Ende einer erfolgreichen Herleitung erkennen. Dazu: Modifiziere die Grammatik: Neues Startsymbol S´ und Regel S´S. Dann: Wenn diese Regel erreicht wird und die gesamte Eingabe gelesen wurde, liegt eine erfolgreiche bottom-up Herleitung vor.

605

Definition T8.2.5 Eine kontextfreie Grammatik G heißt LR(k)Grammatik, falls für alle α,β,γ∈ (V ∪T )*, alle A,B∈V und alle w,x,y∈T * gilt: r r * S´  αAw  αβw r r * S´  γBx  αβy

⇒ α=γ, A=B und y=x.

FIRSTk(w)=FIRSTk(y)

606

Shift-Reduce-Parser Spezieller DPDA, der zusätzlich eine Rechtsableitung berechnet. Aufbau: Eingabeband Lookahead von k

S t a c k

Steuerung mit Übergangstabelle

Ausgabe 607

Übergangstabelle Enthält das „Programm“ des Parsers. Operationen (in Abhängigkeit vom Lookahead und dem obersten Stacksymbol) • Shift: Lies nächstes Zeichen der Eingabe ein und schiebe es auf den Stack. Zusätzlich speichere „Zustand“ auf dem Stack. Aktualisiere Lookahead. • Reduce: Wende eine Regel Aα an. Dazu entferne den zu α gehörenden Stackinhalt und lege A und aktualisierten Zustand auf Stack. • Error/Accept: Rechnung verwerfend/akzeptierend beenden. 608

Reduce-Operation Anwendung der Regel Aβ1…βr • Entferne die obersten 2r Symbole vom Stack (β1,…,βr, sowie die Zustände dazwischen) Weicht vom bisherigen Modell ab, da mehrere Zeichen vom Stack entfernt werden. • Schreibe A auf Stack. • Berechne anhand Tabelle neuen Zustand und lege ihn auf dem Stack ab. 609

Bsp: S´S, SSaSb, Sεε

R0 R1 Lookahead Aktion a b ε T0 R2 error R2 T1 shift error Acc T2 R2 R2 error T3 shift shift error T4 R2 R2 error T5 R1 error R1 T6 shift shift error T7 R1 R1 error Alter Zustand

Oberstes Stacksymbol

R2 neuer Zustand a b S T1 error error error T2 error T3 error error error T4 T5 T6 error error error error error error T4 T7 error error error

610

Wie berechnet man die Tabelle? Algorithmus: • siehe Kapitel T8.3 und T8.4 oder • Aho, A., Sethi, R. und Ullman, J.D. Compilers, Principles, Techniques and Tools, Addison-Wesley, 1986. • Für LR(0)-Parser: http://en.wikipedia.org/wiki/LR_parser Zu aufwändig für diese Vorlesung.

611

Wie berechnet man die Tabelle? Praxis: Verwende Parser-Generator. Eingabe: Kontextfreie Grammatik sowie zusätzliche Befehle, die beim Anwenden der Regeln auszuführen sind. Ausgabe: Parser. Beispiele (für sog. LALR(1)-Gram.): • yacc (yet another compiler compiler) • bison

612

Beispiel: L={w| |w|0=|w|1} Besprochene Grammatik: Sε, S0S1S, S1S0S • bison liefert: shift/reduce conflicts • bedeutet: es gibt Situationen, wo nicht klar ist, ob ein Eingabezeichen zu lesen ist oder eine Regel anzuwenden ist. • Ursache: Grammatik nicht eindeutig. Satz T8.4.10: LR(k)-Grammatiken sind eindeutig. 613

Zusammenfassung • Kontextfreie Grammatiken ermöglichen die Beschreibung von vielen Konstrukten aus den gängigen Programmiersprachen. • Mit Parser-Generatoren kann man auf eine einigermaßen einfache Weise zu speziellen Grammatiken Parser erzeugen. • Die Konstruktion von Compilern, die auch sinnvolle Fehlermeldungen liefern, ist aufwändiger. 614