LR Parser Giuseppe Morelli • La maggior parte dei parser Bottom-Up è costituita dai cosiddetti parser LR(k) dove: • L indica il verso dell’analisi della stringa di input (letf-to-right) • R indica che per la costruzione dell’albero di parse si usa una derivazione destra inversa • K indica il numero di simboli di lookahead utilizzati per le decidere come fare evolvere il procedimento di parsing. • Per k<=1 indichiamo tali parser con LR • I parser LR sono table-driven Vantaggi e svantaggi dei parser LR(k) • Generalità: praticamente tutti i linguaggi di programmazione possono essere riconosciuti con parser LR. • Efficienza: è il metodo shift-reduce bottom-up senza backtracking più generale ed efficiente • Potenza: la classe LR(k) estende la classe LL(k) • Capacità di rilevare errori: un errore viene riconosciuto immediatamente al suo verificarsi. Svantaggi: • Complessità: necessitano appositi tools per la generazione automatica • Un parser Bottom-up , shift-reduce, deve continuamente scegliere se effettuare una operazione di SHIFT o una di REDUCE: Es: Shift * oppure Reduce T con E -> T ???? Stati ed items • La scelta è fatta mantenendo ed utilizzando gli stati, che permettono di tenere traccia circa la “posizione” della situazione di parse. • Gli stati sono insiemi di “items” • Item (item LR(0))di una grammatica G è una produzione di G con un “punto” in una posizione del corpo della stessa. • Es. A ->XYZ • Mentre A -> ε ha item A-> . Canonical LR(0) collection • Un item indica lo stato di avanzamento nell’utilizzo di una produzione in un qualsiasi passo del processo di parsing. • Es. A -> X.YZ indica che è stato già provato che una parte della stringa di input è derivabile da X e si spera il resto sia derivabile da YZ. Mentre A->XYZ. indica che è giunto il momento di ridurre la stringa derivata da XYZ con A. • Una collezione di insiemi di item (stati) (LR(0) Canonical collection) fornisce le basi per la costruzione di un automa a stati finiti deterministico (Automa LR(0)) usato per le decisioni del parser. Ogni stato dell’automa è un insieme di items. Grammatica Aumentata • Per la costruzione della collezione LR(0) canonica di una data grammatica si definisce una grammatica aumentata (argumented grammar) e due funzioni CLOSURE e GOTO. • Se G è una grammatica la grammatica aumentata G’ è una grammatica con: – Tutte le produzioni di G – La nuova produzione S’ -> S con (S simbolo iniziale di G) – S’ simbolo iniziale (G’) • Una stringa è accettata se si applica la produzione S’ -> S CLOSURE (chiusura di insiemi di Item) • Se I è un insieme di Item per la grammatica G allora CLOSURE(I) è costruito seguendo 2 regole: 1. In CLOSURE (I) vengono aggiunti tutti gli Item già presenti in I 2. Se A -> α.Bβ è in CLOSURE(I) e B -> γ è una produzione allora si aggiunge a CLOSURE (I) anche l’item B ->.γ ( se non c’è ancora). Tale regola si applica finchè si possono aggiungere elementi. Esempio • Supponiamo sia I ={[E’->.E]} un insieme di items della grammatica aumentata seguente F • CLOSURE(I) ={ [E’->.E], [E->.E+T], [E->.T], [T->.T*F],[T->.F], [F->.(E)], [F->.id] } Algoritmo GOTO • La funzione GOTO permette di definire le transizioni nell’automa LR(0) canonico di una grammatica; GOTO(I,X) con I insieme di items, X un simbolo della grammatica è definito come: GOTO(I,X) = CLOSURE {A -> αX.β : A -> α.Xβ Є I } • Esempio: – Se I = E’ -> .E allora GOTO(I, E) = {[E’->E.], E’->E. β} Calcolo della collezione canonica LR(0) QuickTime™ e un decompressore sono necessari per visualizzare quest'immagine. SLR • Concetto chiave la costruzione dell’ LR(0) automa. • Gli stati dell’automa sono gli insiemi di Item della collezione canonica LR(0) e le transizioni sono determinate dalla funzione GOTO • Lo stato iniziale coincide con CLOSURE({[S’->.S]}) • La scelta di SHIFT o REDUCE è fatta come segue: – Se la stringa γ porta l’automa LR(0) dallo stato 0 allo stato j; se lo stato j ha una transizione etichettata con il successivo simbolo di input a, allora si sceglierà di shiftare a, altrimenti si riduce con la produzione indicata allo stato j. F Classificazione di item • Kernel items: – S’->.S – A->α.Bβ con α != ε • Non Kernel items: – A-> .β con β != S Algoritmo di Parsing INPUT a1 … ai an $ STACK sn Xn . . . PROGRAMMA DI PARSING LR X1 s1 ACTION GOTO OUTPUT Alcune note • Come mostra la figura un parser LR consiste di un input, un output, un programma di controllo, uno stack ed infine una tabella di parsing che ha due parti (ACTION e GOTO) • Il programma di controllo è lo stesso per tutti i parser LR • La differenza tra parser LR è determinata dalla tabella di parsing • Lo stack contiene una sequenza di stati che nel caso di SLR parser corrispondono a quelli dell’automa LR(0). • Per costruzione ogni stato coincide con un insieme di items ovvero Ij = GOTO(Ii,X) rappresenta una transizione dallo stato i allo stato j. • Ad ogni stato eccetto che a quello iniziale è possibile associare un solo simbolo della grammatica Struttura della tabella di parsing LR • Tale tabella consiste di: – ACTION: Una funzione per le azioni del parser che prende come argomenti uno stato i ed un simbolo terminale a e restituisce ACTION[i,a] come segue: • = Shift j (con j uno stato): in effetti è il simbolo che deve essere shiftato ma come visto in precedenza c’è una corrispondenza tra simbolo e stato. • = Reduce A->β: viene sostituito β (top dello stack) con la testa della produzione A • = Accept: il processo di parsing finisce accettando l’input • = Error: l’input non è riconosciuto ed il parser genera errore. – GOTO:Viene estesa agli stati i e j la funzione GOTO[Ii, A] = Ij applicata e definita per gli insiemi di Item • Input: stringa w e tabella di Parsing LR per G • Output: riduzione al simbolo iniziale a partire da w se w appartiene a L(G) altrimenti errore Definizione dell’insieme FOLLOW • Dato un simbolo non terminale A si definisce FOLLOW(A) l’insieme di simboli terminali che appaiono immediatamente alla destra di A in una forma proposizionale. Ovvero l’insieme di simboli terminali a per i quali esiste una derivazione della forma S =>αAaβ per qualche α e β. • Il calcolo di FOLLOW avviene: – Si posizione $ nel FOLLOW(S) S= simbolo iniziale – Se esiste una produzione del tipo A->αBβ allora gli elementi di FIRST(β) si aggiungono in FOLLOW(B) escludendo ε – Se esiste una produzione A->αB o una produzione A->αBβ con ε Є FIRST(β) allora FOLLOW(B) conterrà tutto FOLLOW(A). Costruzione della tabella SLR • Data G si costruisce la grammatica aumentata G’ quindi: 1. Si costruisce la collezione canonica LR(0) (insiemi di Items) c = {I0, I1, …. ,In} 2. Lo stato i è costruito da Ii. L’azione per lo stato i è determinata come segue: a) Se [A-> α.aβ] è in Ii e GOTO(Ii,a) = Ij allora ACTION[i,a] = “shift j” b) Se [A-> α.] è in Ii allora ACTION[i,a] = “reduce A-> α” per ogni a Є FOLLOW(A) c) Se [S’ -> S.] è in Ii allora ACTION[i, $] = “accept” 3. GOTO deve essere costruita per tutti i non termiali Secondo la regola se GOTO(Ii,a)=Ij allora GOTO(i,a) =j 4. Errore se vi sono entry non definit da 2 e 3 5. Lo stato iniziale è quello ottenuto dall’insieme di Item contenente [S’->S] Esempio • Consideriamo la grammatica aumentata S’=I I->S S->B S->Caa B->bC C->bbCa C->e Per costruire la tabella SLR Calcoliamo FOLLOW dei Non terminali e l’insieme di items LR(0) Follow(I): $ Follow(S): $ Follow(B): $ Follow(C): a$ I0 I->°S S->°B S->°Caa B->°bC C->°bbCa C->e° S I1 I->S° B I2 a S->B° C I3 S->C°aa I5 S->Ca°a a I6 B->bC° C b I4 B->b°C C->b°bCa C->°bbCa C->e° I8 S->Caa° b I7 C->bb°Ca C->b°bCa C->°bbCa C->e° C I9 C->bbC°a a I10 C->bbCa° Stringa “bbba” Goto (4,C)