82
LFC Parsing di linguaggi liberi Introduzione Parsing top-down Parsing bottom-up Linguaggi formali e compilazione Corso di Laurea in Informatica A.A. 2008/2009

Linguaggi Formali e Compilazione: Parsing

Embed Size (px)

Citation preview

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Linguaggi formali e compilazioneCorso di Laurea in Informatica

A.A. 2008/2009

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Linguaggi formali e compilazione

Parsing di linguaggi liberiIntroduzioneParsing top-downParsing bottom-up

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Linguaggi formali e compilazione

Parsing di linguaggi liberiIntroduzioneParsing top-downParsing bottom-up

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Parsing di linguaggi liberi

◮ Ogni linguaggio libero può essere riconosciuto intempo proporzionale al cubo della lunghezza dellastringa in input.

◮ L’algoritmo che stabilisce questo limite dicomplessità, basato su una classica applicazionedella programmazione dinamica, è tuttaviainutilizzabile in applicazioni reali.

◮ Gli algoritmi di parsing utilizzati nella pratica sonogeneralmente classificati base alla strategia utilizzataper la costruzione (anche solo “ideale”) delparse-tree, top-down o bottom-up.

◮ All’interno di queste due categorie generali, glialgoritmi si differenziano in base a scelte strategichepiù dettagliate.

◮ Tali algoritmi non possono analizzare tutti i linguaggicontext-free.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Tipi di parser

◮ In concreto, i tipi di parser più diffusi includono:◮ parser a discesa ricorsiva (top-down),◮ parser di tipo LR (bottom-up),◮ parser a precedenza di operatori (bottom-up).

◮ Nel parsing top-down si cerca una derivazionecanonica per la stringa/programma in input partendodall’assioma iniziale.

◮ La costruzione top-down dell’albero di derivazionecorrisponde in modo naturale al riconoscimento di unblocco/procedura/espressione in termini delle particostituenti.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Tipi di parser (continua)

◮ Nel parsing bottom-up si cerca una derivazionecanonica per la stringa/programma in input partendodalla stringa stessa e applicando riduzionisuccessive.

◮ Una riduzione non è nient’altro che l’applicazione “insenso contrario” di una produzione della grammatica.

◮ La costruzione bottom-up dell’albero di derivazionecorrisponde in modo naturale al riconoscimento disingole porzioni di un programma e alla lorocomposizione in parti più complesse.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Non determinismo

◮ In entrambi i tipi di parser (top-down o bottom-up) èpossibile (anche se non desiderabile) che la sceltadella produzione da utilizzare, in una delle duedirezioni, non sia determinabile con certezza.

◮ Se la scelta di una produzione è “errata” ilriconoscimento fallisce.

◮ In tal caso, prima di dichiarare che la stringa èsintatticamente errata, è necessario operare unbacktracking sull’input, ritornando al punto di scelta.

◮ Per i parser a discesa ricorsiva (e implementatimediante ricorsione) ciò può essere sufficientementeagevole, anche se computazionalmente pesante.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Linguaggi formali e compilazione

Parsing di linguaggi liberiIntroduzioneParsing top-downParsing bottom-up

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Parsing a discesa ricorsiva (recursivedescent)

◮ Un parser a discesa ricorsiva (d.r.) può essererealizzato come collezione di procedure(mutuamente) ricorsive, una per ogni simbolo nonterminale della grammatica.

◮ Siano A→ α1 . . . αk le produzioni relative alnonterminale A, e sia αi = X i

1 . . . X ini

, i = 1, . . . , k .◮ La procedura relativa al simbolo A è illustrata nel

seguente algoritmo, in cui (per semplicità dinotazione) evitiamo i doppi indici e supponiamo cheil simbolo corrente di input sia contenuto nellavariabile globale x .

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-upAlgorithm 1 Procedura per il nonterminale A1: Scegli “opportunamente” una produzione A →

X1X2 . . . Xk (Xj ∈ V)2: for j = 1, . . . , k do3: if Xj ∈ N then4: Xj()5: else if Xj = x then6: x ← read()7: else8: error()

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Backtracking

◮ La scelta della produzione da applicare (riga 1dell’algoritmo 1) può essere meno critica se, nel casodi fallimento, viene effettuato backtracking sull’input.

◮ L’algoritmo deve essere modificato in modo tale dadichiarare fallimento solo quando tutte le produzioniper il nonterminale A sono state provate senzasuccesso.

◮ Deve però essere disposto un meccanismo perriposizionare il puntatore di input su quello che era ilsimbolo corrente al momento della chiamata dellaprocedura.

◮ Ne consegue che: o il parser bufferizza l’inputricevuto dallo scanner, oppure è quest’ultimo chedeve essere opportunamente programmato per laripetizione di certe sequenze di token.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Scelta della produzione

◮ Fortunatamente, in molti casi concreti il backtrackingnon è necessario perché la scelta della produzionepuò essere fatta con lookahead limitato (cioèguardando pochi token a partire dalla posizionecorrente di input).

◮ Consideriamo la semplice grammatica:

A → aA | bB

B → ǫ | bB

◮ Per entrambi i non terminali, la scelta dellaproduzione da usare può essere fatta guardando ilprossimo simbolo x in input.

◮ Per A: se x = a, usa la produzione A→ aA; sex = b, usa la produzione A→ bB.

◮ Per B. se x = $ (end of input), usa la produzioneB → ǫ; se x = b, usa la produzione B → bB;

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Grammatiche inadatte al parsing a discesaricorsiva

◮ Alcune produzioni sono inadatte al r.d. parsing.◮ Produzioni con ricorsioni a sinistra, che possono

causare cicli infiniti, come nella grammatica

E → E+T | T

T → T∗F | F

F → id | (E)

◮ Produzioni con prefissi comuni (come il noto caso del“dangling else”), che rendono non limitabile a priori laquantità di lookahead. Un altro esempio (artificiale) è

A → aB | aC

B → aB | b

C → aC | c

◮ Come sappiamo, esistono opportune trasformazioniper risolvere questi problemi.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

FIRST e FOLLOW◮ Data una grammatica G, l’implementazione di parser

a d.r. per G utilizza (secondo le “teorie” più accettate)due funzioni, dette FIRST e FOLLOW , chedeterminano la scelta della produzione da utilizzare.

◮ Data G = (N ,T ,P,S) e data una stringaα ∈ (N ∪ T )∗, si definisce FIRST (α) l’insieme deisimboli terminali con cui può iniziare una frasederivabile da α, più eventualmente ǫ se α⇒∗ ǫ:

FIRST (α) = {x ∈ T |α⇒∗ xβ, β ∈ T ∗}

∪ {ǫ} , se α⇒∗ ǫ.

◮ Per ogni nonterminale A ∈ N si definisceFOLLOW (A) l’insieme dei terminali che si possonotrovare immediatamente alla destra di A in unaqualche forma di frase. In altri termini,x ∈ FOLLOW (A) se S ⇒∗ αAxβ, con α e β

opportuni.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Calcolo di FIRST (α)

◮ Definiamo innanzitutto come si calcola FIRST (α) nelcaso in cui α sia un singolo simbolo dellagrammatica, cioè α = X con X ∈ N ∪ T .

◮ Se X è un terminale, si pone naturalmenteFIRST (X) = {X};

◮ se X è un nonterminale poniamo innanzituttoFIRST (X) = {}.

◮ Se esiste la produzione X → X1 . . . Xn, e risultaǫ ∈ FIRST (Xj), j = 1, . . . , k − 1, poniamoFIRST (X ) = FIRST (X ) ∪ {x} per ogni simbolox ∈ FIRST (Xk).

◮ Infine, se esiste la produzione X → ǫ oppureǫ ∈ FIRST (Xj), j = 1, . . . , k , poniamoFIRST (X ) = FIRST (X ) ∪ {ǫ}.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempi◮ Si consideri nuovamente la grammatica

E → (E) E ′ | id E ′

E ′ → + E E ′ | × E E ′ | ǫ

◮ Per questa grammatica risulta◮ FIRST (E) = {( , id}◮ FIRST (E ′) = {+,×, ǫ}

◮ Si consideri ora la grammatica per anbmck

A → aA | BC | ǫ

B → bB | ǫ

C → cC | ǫ

◮ Per questa grammatica risulta◮ FIRST (C) = {c, ǫ}◮ FIRST (B) = {b, ǫ}◮ FIRST (A) = {a,b,c, ǫ}

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Si riconsideri la grammatica per le espressioni che“forza” la precedenza di operatori:

E → E + T | T

T → T × F | F

F → id | (E)

◮ Per questa grammatica risulta◮ FIRST (F ) = {( , id};◮ FIRST (T ) = FIRST (F );◮ FIRST (E) = FIRST (T ).

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Calcolo di FIRST (α) (continua)

◮ Il calcolo di FIRST (α), dove α = X1 . . . Xn è unagenerica stringa di terminali e nonterminali, può oraessere svolto nel modo seguente

◮ a ∈ FIRST (α) se e solo se, per qualche indicek ∈ 1, . . . n − 1, risulta a ∈ Xk e ǫ ∈ Xj ,j = 1, . . . , k − 1 (si suppone sempre ǫ ∈ FIRST (X0)).

◮ Se inoltre ǫ ∈ FIRST (Xj), j = 1, . . . , n, alloraǫ ∈ FIRST (α).

◮ Ad esempio, nel caso della seconda grammatica dellucido precedente risulta: FIRST (aA) = {a} eFIRST (BC) = {b,c, ǫ}.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Calcolo di FOLLOW (A)

◮ Il calcolo di FOLLOW (A), per un generico nonterminale A, può essere svolto in questo modo.

◮ Se A = S, si inserisce il simbolo speciale $(marcatore di fine input) in FOLLOW (A).

◮ Se esiste la produzione B → αAβ, tutti i terminali inFIRST (β) si inseriscono in FOLLOW (A); inoltre, seǫ ∈ FIRST (β), tutti i terminali che stanno inFOLLOW (B) si inseriscono in FOLLOW (A) .

◮ Analogamente, se esiste la produzione B → αA, tuttii terminali che stanno in FOLLOW (B) si inserisconoin FOLLOW (A) .

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Consideriamo la solita grammatica

E → (E) E ′ | id E ′

E ′ → + E E ′ | × E E ′ | ǫ

◮ Possiamo subito stabilire che FOLLOW (E) include ilsimbolo $ e il simbolo ); inoltre contiene i simboli inFIRST (E ′) (eccetto ǫ) e cioè + e ×.

◮ FOLLOW (E ′) include FOLLOW (E), a causa (adesempio) della produzione E → idE ′.

◮ La produzione E ′ → +EE ′, unitamente a E ′ → ǫ,stabilisce che vale anche il contrario, e cioè cheFOLLOW (E) include FOLLOW (E ′).

◮ Mettendo tutto insieme si ottieneFOLLOW (E) = FOLLOW (E ′) = {$, ) ,+,×}.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Per la grammatica

A → aA | BC | ǫ

B → bB | ǫ

C → cC | ǫ

risulta FOLLOW (A) = FOLLOW (C) = {$} eFOLLOW (B) = {c, $}.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Per la grammatica con precedenza di operatori:

E → E + T | T

T → T × F | F

F → id | (E)

risulta:◮ FOLLOW (E) = {$, +, )};◮ FOLLOW (T ) = FOLLOW (E) ∪ {×};◮ FOLLOW (F ) = FOLLOW (T ).

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Grammatiche LL(1)

◮ Per opportune classi di grammatiche libere èpossibile realizzare parser a d.r. che non richiedonobacktracking (tali parser sono anche detti predittivi).

◮ Una tale classe di grammatiche è la LL(1), dove ledue L stanno per “left-to-right” e “leftmost derivation”.

◮ In altri termini, il parsing avviene leggendo l’inputunidirezionalmente, da sinistra a destra, ecostruendo una derivazione canonica sinistra dellastringa. Il parametro 1 indica che è richiesto un solosimbolo di lookahead.

◮ La classe LL(1) è in grado di esprimere molte fra lecaratteristiche della sintassi dei linguaggi diprogrammazione.

◮ Nessuna grammatica ricorsiva a sinistra o conproduzioni aventi previssi comuni può però essereLL(1) (come pure nessuna grammatica ambigua).

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Grammatiche LL(1) (continua)

◮ Come possiamo stabilire se una grammatica èLL(1)?

◮ Consideriamo la procedura per un genericononterminale A.

◮ Se esistono due produzioni A→ α e A→ β, alloracertamente non deve accadere che

FIRST (α) ∩ FIRST (β) 6= {} ,

perché in tal caso un solo carattere di lookahead nonbasterebbe per decidere correttamente laproduzione da usare.

◮ Tuttavia ciò potrebbe non essere sufficiente.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Grammatiche LL(1) (continua)

◮ Supponiamo (ad esempio) che α⇒∗ ǫ. Potremmotrovarci nella seguente situazione:

S ⇒∗ γAxδ, γ ∈ T ∗, x ∈ T , δ ∈ V∗

dove, se il prossimo carattere di input fosse propriox , potrebbe essere corretto usare la produzioneA→ α.

◮ Tuttavia, se x fosse anche in FIRST (β) potrebbeessere corretto pure usare la produzione A→ β.

◮ Deve quindi risultare α⇒∗ ǫ implicaFOLLOW (A) ∩ FIRST (β) = {} e, analogamente,β ⇒∗ ǫ implica FOLLOW (A) ∩ FIRST (α) = {}

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio◮ Si consideri la grammatica

A → B E

B → C | D

C → ǫ | cc

D → ǫ | dd

E → c | d

◮ Poiché risulta FIRST (C) ∩ FIRST (D) = {ǫ}, lagrammatica non è LL(1).

◮ Infatti, supponiamo che la stringa in input inizi con c.Dopo la riscrittura dell’assioma il parser verrebbe atrovarsi con la forma di frase BE e il carattere c ininput.

◮ A questo punto potrebbe essere corretto derivaretanto CE (se l’input fosse, ad esempio, ccd) quantoDE (se l’input fosse c).

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio◮ Si modifichi la precedente grammatica nel modo

seguente

A → B E

B → C | D

C → ǫ | cc

D → dd

E → c | d

(cancellando cioè la produzione D → ǫ).◮ Poiché risulta FIRST (D)∩ FOLLOW (B) = {d}, la

grammatica non è LL(1).◮ Il problema si verifica con input che inizia con d,

perché potrebbe essere corretto (dopo la derivazioneiniziale) derivare tanto CE (se l’input fosse d) quantoDE (se l’input fosse, ad esempio ddc).

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Costruzione della tabella di parsing

◮ Per una grammatica LL(1) è possibile costruire(utilizzando le funzioni FIRST e FOLLOW ) unatabella, detta tabella di parsing, che, per ogninonterminale A e ogni terminale x , prescrive ilcomportamento del parser.

◮ Indicheremo con MG la tabella di parsing relativa allagrammatica G (o semplicemente con M, se lagrammatica è evidente).

◮ La generica entry MG[A, x ] della tabella puòcontenere una produzione A→ α di G, oppureessere vuota, ad indicare che si è verificato unerrore.

◮ Disponendo di MG, la prima riga dell’algoritmo 1viene sostituita da un lookup a MG[A, x ].

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Costruzione della tabella di parsing(continua)

◮ L’algoritmo di costruzione della parsing table è moltosemplice ed è formato da un ciclo principale nelquale si prendono in considerazione tutte leproduzioni.

◮ Per ogni produzione A→ α:◮ per ogni simbolo x in FIRST (α) si pone

M[A, x ] = ‘A→ α′;◮ se ǫ ∈ FIRST (α), per ogni simbolo y in FOLLOW (A)

si pone M[A, y ] = ‘A→ α′.

◮ Tutte le altre entry della tabella vengono lasciatevuote (ad indicare l’occorrenza di un errore).

◮ Se la grammatica è LL(1), nessuna entry dellatabella viene riempita con più di una produzione.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio◮ Consideriamo ancora la grammatica con precedenza

di operatori:

E → E + T | T

T → T × F | F

F → id | (E)

◮ Tale grammatica (pur non ambigua) non è LL(1)perchè (p.e.), entrambe le produzioni E → E + T eE → T verrebbero poste nella entry M[E , id].

◮ Eliminando la left-recursion si può però ottenere unagrammatica equivalente che è LL(1):

E → TE ′

E ′ → +TE ′ | ǫ

T → FT ′

T ′ → ×FT ′ | ǫ

F → id | (E)

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)◮ Per la grammatica modificata

E → TE ′

E ′ → +TE ′ | ǫ

T → FT ′

T ′ → ×FT ′ | ǫ

F → id | (E)

abbiamo:◮ FIRST (F ) = FIRST (T ) = FIRST (E) = {id, (};◮ FIRST (E ′) = {+, ǫ};◮ FIRST (T ′) = {×, ǫ};◮ FOLLOW (E) = FOLLOW (E ′) = {$, )};◮ FOLLOW (T ) = (FIRST (E ′)\ {ǫ}) ∪ FOLLOW (E ′) ={+, $, )};

◮ FOLLOW (T ′) = FOLLOW (T ) = {+, $, )};◮ FOLLOW (F ) = (FIRST (T ′)\ {ǫ}) ∪ FOLLOW (T ′) ={×, +, $, )}.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)

◮ L’algoritmo produce la seguente tabella di parsing

N.T.Simbolo di input

id ( ) + × $E E → TE′ E → TE′

E′ E′ → ǫ E′ → +TE′ E′ → ǫ

T T → FT ′ T → FT ′

T ′ T ′ → ǫ T ′ → ǫ T ′ → ×FT ′ T ′ → ǫ

F F → id F → (E)

in cui le entry vuote corrispondono ad una situazionedi errore.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Se tentassimo di produrre la tabella di parsing per lagrammatica

E → (E) E ′ | id E ′

E ′ → + E E ′ | × E E ′ | ǫ

otterremmo

N.T.Simbolo di input

id ( ) + × $E E → idE′ E → (E)E′

E′ E′ → ǫ

E′ → +EE′ E′ → ×EE′

E′ → ǫ

E′ → ǫ E′ → ǫ

◮ Con in input il carattere + o il carattere ×, il parsernon saprebbe quindi come procedere.

◮ Il non soddisfacimento delle proprietà LL(1) è unaconseguenza dell’ambiguità della grammatica.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)

◮ In questo caso è comunque possibile forzare nelparser una regola di scelta senza compromettere lacapacità di riconoscere il linguaggio generato dallagrammatica.

◮ Possiamo (anzi, dobbiamo!) semplicemente optarein favore delle produzioni E ′ → +EE ′ e E ′ → ×EE ′,anziché E ′ → ǫ.

◮ Si noti comunque che, pur avendo risolto l’ambiguità,l’interpretazione delle espressioni che derivadall’albero di parsing non è quella “naturale” (nonviene soddisfatta la precedenza naturale deglioperatori).

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio◮ Consideriamo la seguente grammatica:

S → i E t S e S | i E t S | a

E → b

che mette a fuoco il problema del dangling else dimolti linguaggi e che, avendo produzioni con unprefisso comune, non è idonea al parsing a d.r.

◮ Operando nel modo già illustrato, otteniamo:

S → i E t S S′ | a

S′ → e S | ǫ

E → b

e risulta◮ FIRST (S) = {i, a};◮ FIRST (S′) = {e, ǫ};◮ FIRST (E) = {b};◮ FOLLOW (S) = FOLLOW (S′) = {$, e}.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)

◮ La grammatica modificata è non è ancora LL(1) inquanto FIRST (eS) ∩ FOLLOW (S′) = {e}.

◮ Ciò si riflette in una definizione multipla per una entrydella tabella di parsing:

N.T.Simbolo di input

i t e a b $S S → iEtSS′ S → a

S′ S′ → eSS′ → ǫ

S′ → ǫ

E E → b

◮ Tuttavia se, con in input il carattere e, il parservenisse “istruito” a scegliere sempre la produzioneS′ → eS, l’ambiguità si risolverebbe (e pure conl’intepretazione “naturale”, che associa ogni else althen più vicino).

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Implementazione non ricorsiva

◮ È possibile dare un’implementazione non ricorsiva diun parser predittivo (cioè che non richiedebacktracking) mantenendo esplicitamente una pila.

◮ La pila serve per memorizzare i simboli della partedestra della produzione scelta.

◮ Tali simboli verranno poi “confrontati” con l’input (seterminali) o ulteriormente riscritti (se non terminali).

◮ Il comportamento del parser può essere descritto nelmodo seguente.

◮ Inizialmente, sullo stack sono contenuti (partendo dalfondo) i simboli $ ed S, mentre un opportunopuntatore (diciamo z) punta al primo carattere diinput.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Implementazione non ricorsiva (continua)

◮ Al generico passo, il parser controlla il simbolo Xsulla testa dello stack;

◮ se X è un nonterminale e M[X , z] = ‘X → X1 . . . Xk ‘,esegue una pop dallo stack (rimuove cioè X ) seguitada k push dei simboli X1, . . . , Xk , nell’ordine;

◮ se X è un nonterminale e M[X , z] = ‘error ‘, segnalauna condizione di errore;

◮ se X è un terminale e X = z, esegue una pop e faavanzare z;

◮ se X è un terminale e X 6= z, segnala unacondizione di errore.

◮ Le operazioni terminano quando X = $.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Consideriamo nuovamente la grammatica delleespressioni con precedenza di operatore, della qualericordiamo la tabella di parsing:

N.T.Simbolo di input

id ( ) + × $E E → TE′ E → TE′

E′ E′ → ǫ E′ → +TE′ E′ → ǫ

T T → FT ′ T → FT ′

T ′ T ′ → ǫ T ′ → ǫ T ′ → ×FT ′ T ′ → ǫ

F F → id F → (E)

◮ Supponendo di avere la stringa id + id in input, laseguente tabella illustra il progressivo contenutodello stack e dell’input.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)

Stack Input$E id + id$$E ′T id + id$$E ′T ′F id + id$$E ′T ′id id + id$$E ′T ′ +id$$E ′ +id$$E ′T+ +id$$E ′T id$$E ′T ′F id$$E ′T ′id id$$E ′T ′ $$E ′ $$ $

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esercizi proposti

◮ Si calcolini gli insiemi FIRST e FOLLOW per laseguente grammatica:

S → c | AS | BS

A → aB | ǫ

B → bA | ǫ

e si costruisca la relativa tabella di parsing per unparser a discesa ricorsiva.

◮ Si calcolino gli insiemi FIRST e FOLLOW per lagrammatica G2, che descrive le espressioni regolarisu {0, 1}, dopo averla modificata in modo daeliminare i prefissi comuni. Se ne costruisca quindi latabella di parsing per un parser a discesa ricorsiva.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Linguaggi formali e compilazione

Parsing di linguaggi liberiIntroduzioneParsing top-downParsing bottom-up

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Elementi generali

◮ Un parser generico di tipo bottom-up procedecercando di operare riduzioni, operazioni chepossiamo vedere come l’inverso delle derivazioni, apartire dalla stringa di input α0 = α.

◮ Al generico passo di riduzione il parser individua,nella stringa corrente αi , un’opportuna sottostringa β

che corrisponde alla parte destra di una produzioneA→ β e sostituisce β con A, così riducendo αi adαi+1:

αi = γβδ, αi+1 = γAδ

◮ Il processo termina con successo se, per unopportuno valore di i , risulta αi = S.

◮ Nell’ambito del processo di riduzione il parser puòcostruire (dal basso verso l’alto) un albero diderivazione e/o produrre codice.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Parsing “Shift-reduce”

◮ Un parser shift-reduce è un parser di tipo bottom-upche fa uso di uno stack nel quale vengonomemorizzati simboli (terminali o non terminali) dellagrammatica.

◮ Il nome deriva dal fatto che le due operazionifondamentali eseguite del parser sono dette,appunto, shift e riduzione.

◮ L’operazione di shift legge un simbolo dallo stream diinput e lo inserisce sullo stack.

◮ L’operazione di riduzione sostituisce sullo stack gliultimi k simboli inseriti (poniamo X1, . . . , Xk ) con ilsimbolo A, naturalmente se esiste la produzioneA→ X1 . . . Xk .

◮ Le altre operazioni che il parser esegue sonol’accettazione dell’input e la segnalazione di unacondizione di errore.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Maniglie (handle)

◮ Un parser di tipo shift-reduce deve individuare, comesottostringhe da ridurre a non terminale, non giàqualunque sequenza che formi la parte destra di unaproduzione, bensì esattamente quelle sequenze (equelle produzioni) usate nella derivazione canonicadestra.

◮ Tali sequenze devono inoltre essere individuate“nell’ordine giusto”, e cioè l’ordine rovesciato rispettoalla corrispondente derivazione canonica destra.

◮ Queste sequenze (ma meglio sarebbe dire“produzioni”) vengono chiamate handle (maniglie), dimodo che il problema centrale della realizzazione diun tale parser può essere espresso sinteticamentecome il problema di individuare le maniglie.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio◮ Si consideri la grammatica:

E → E + T | T

T → T × F | F

F → id | (E)

◮ La corretta riduzione di id + id× id ad E individua lemaniglie indicate dalla sottolineatura:

id + id× id ⇐ F + id× id

⇐ T + id× id

⇐ E + id× id

⇐ E + F × id

⇐ E + T × id

⇐ E + T × F

⇐ E + T

⇐ E

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Maniglie (continua)

◮ In un parser shift-reduce le successive stringhe αi

(che rappresentano la trasformazione dall’inputall’assioma) si trovano “parte sullo stack e parteancora sullo stream di input“.

◮ In particolare, non sarebbe difficile dimostrare che,se il parser ricostruisce (in ordine inverso) derivazionicanoniche destre, la maniglie appaiono sempre sullacima dello stack.

◮ Ad esempio, se αi = γβδ e β è una maniglia, alloraγβ sta sullo stack (nell’ordine, dal fondo verso lacima) mentre δ sta ancora nello stream di input.

◮ La maniglia, in questo caso β, sta sulla cima dellostack e viene “sostituita” con A dall’operazione diriduzione.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio◮ Azioni eseguite (su input id + id× id) da un parser

shift-reduce che riconosce correttamente le maniglie.

Stack Input Azione Stringa αi

$ id + id× id$ shift id + id × id$$id +id× id$ reduce id + id × id$$F +id× id$ reduce F + id× id$$T +id× id$ reduce T + id× id$$E +id× id$ shift E + id× id$$E+ id× id$ shift E + id× id$$E + id ×id$ reduce E + id× id$$E + F ×id$ reduce E + F × id$$E + T ×id$ shift E + T × id$$E + T× id$ shift E + T × id$$E + T × id $ reduce E + T × id$$E + T × F $ reduce E + T × F$$E + T $ reduce E + T$$E $ accept E$

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)

◮ Si noti che, nella colonna azione, bisognerebbecorrettamente indicare, nel caso di riduzione, qualeproduzione va utilizzata.

◮ In generale, la stessa parte destra potrebbe infatticorrispondere a più di una produzione (non è questoil caso), ed è per questo motivo che si definiscono lehandle come produzioni e non come semplicisequenze.

◮ Si noti inoltre come le maniglie “corrette”(corrispondenti alla derivazione canonica destra)appaiano effettivamente sempre sulla cima dellostack.

◮ Questa proprietà non varrebbe nel caso volessimoriprodurre, poniamo, una derivazione canonicasinistra.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Il cuore computazionale del problema

◮ La difficoltà di progettazione del parser sta tutta nellacapacità di riconoscere quando è corretto operareuno shift e quando invece è corretto operare unariduzione.

◮ Il problema coincide con quello di determinareesattamente le maniglie. Infatti, se fossimo in gradodi risolvere quest’ultimo sapremmo sempre quando“shiftare” e quando “ridurre”.

◮ Dovremmo infatti ridurre quando e solo quando unamaniglia appare sulla cima dello stack.

◮ Sfortunatamente ci sono grammatiche per le quali ilparadigma shift-reduce non è applicabile, adesempio grammatiche ambigue.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esercizi proposti

◮ Per la grammatica

S → (S)S | ǫ

si tracci (sulla falsariga di quanto visto nell’esempiodi slide 48) il comportamento di un parsershift-reduce su input (()()) e ()(()), nell’ipotesi che ilparser sia in grado di individuare correttamente lemaniglie.

◮ Si verifichi l’esistenza di un conflitto shift-reduce perla grammatica che astrae il problema deldangling-else nei linguaggi di programmazione (slide35)

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Parser LR

◮ Si tratta di una classe di parser di tipo shift-reduce(con analisi dell’input da sinistra a destra, “Left toRight”), caratterizzati da una struttura di programmacomune ma con capacità di analisi diverse.

◮ La diversa capacità di effettuare il parsing dipendedall’informazione contenuta in apposite tabelle diparsing che guidano il comportamento delprogramma.

◮ In questi appunti analizzeremo un solo tipo di parserLR, il più semplice, che prende (non a caso) il nomedi (parser) SLR(1).

◮ Per prima cosa vedremo però la “program structure”comune.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Struttura di un parser LR

◮ Un parser LR è caratterizzato da un programma dicontrollo (essenzialmente un automa a stati finiti) cheha accesso ad uno stack e ad una tabella di parsing,oltre che a opportuni supporti di input e output.

◮ Le tabelle prescrivono il comportamento delprogramma di controllo esclusivamente in funzionedel contenuto dello stack e dei primi k caratteripresenti in input.

◮ Il valore di k è uno dei parametri che rende più omeno potente il parser (nel seguito vedremo solo ilcaso k = 1)

◮ Lo stack, a differenza dei parser shift-reduce vistiprecedentemente, contiene stati anziché simboli.Tuttavia, come vedremo, ad ogni stato è associatounivocamente un simbolo della grammatica.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Tabelle di parsing

◮ Le tabelle di parsing di un parser LR hanno unnumero di righe pari al numero di stati dell’automache costituisce il controllo.

◮ Le colonne sono indicizzate dai simboli terminali enon terminali. Le colonne relative ai terminaliformano quella che viene detta “parte ACTION” dellatabella, mentre le altre formano la “parte GOTO”.

◮ Nella parte action sono previste 4 tipi di azioni:◮ avanzamento di un carattere sullo stream di input e

inserimento di uno stato in cima allo stack;◮ utilizzo di una riduzione;◮ accettazione dell’input;◮ rilevamento di un errore.

◮ La parte GOTO prescrive stati da inserire nello stack.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Funzionamento del parser◮ Il funzionamento del parser è definito come segue.◮ Inizialmente, lo stack contiene un solo stato (lo stato

iniziale, naturalmente).◮ Al generico passo, sia q lo stato in cima allo stack e

x il prossimo carattere in input.◮ Se ACTION [q, x ] = shift r , il parser avanza il

puntatore di input e inserisce lo stato r sullo stack.◮ Se ACTION [q, x ] = reduce i , il parser utilizza la

i-esima produzione (secondo una numerazionearbitraria ma prefissata). Più precsamente, se A→ α

è tale produzione, il parser rimuove ki = |α| statidallo stack e vi inserisce lo stato GOTO [q′, A] doveq′ è lo stato sulla cima dello stack dopo le ki

rimozioni.◮ Il parser si arresta (naturalmente) in seguito ad

accettazione o errore.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Consideriamo la grammatica che genera sequenzedi parentesi bilanciate:S → (S)S Produzione 1S → ǫ Produzione 2

e consideriamo la sguente tabella di parsing (di cuivedremo più avanti la costruzione):

StatoACTION GOTO

( ) $ S0 shift 2 reduce 2 reduce 2 11 accept2 shift 2 reduce 2 reduce 2 33 shift 44 shift 2 reduce 2 reduce 2 55 reduce 1 reduce 1

◮ Consideriamo il comportamento del parser su input()().

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)Stack Input Azione$0 ()()$ shift 2$02 )()$ reduce S → ǫ

$023 )()$ shift 4$0234 ()$ shift 2$02342 )$ reduce S → ǫ

$023423 )$ shift 4$0234234 $ reduce S → ǫ

$02342345 $ reduce S → (S)S$02345 $ reduce S → (S)S$01 $ accept

◮ Si ricordi che la riduzione con S → (S)S primarimuove 4 stati dallo stack, quindi inserisce lo statoGOTO[q′, S], dove q′ è lo stato che rimane in cimaallo stack dopo le rimozioni.

◮ Analogamente, la riduzione con S → ǫ rimuove 0stati.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Parsing SLR(1)

◮ Il primo tipo di parser LR che analizziamo è dettoSimple LR parser (o semplicemente SLR).

◮ È caratterizzato da tabelle di parsing di relativamentesemplice costruzione (da cui il nome) ma che dannominori garanzie sulla possibilità di analisi digrammatiche libere.

◮ In altri termini, ci sono diverse grammatiche libere diinteresse che non possono essere analizzate conparser SLR (e, segnatamente, SLR(1)).

◮ Si tratta comunque di un primo caso di interesse percapire la “logica” di un parser LR.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Automa LR(0)◮ Il passo fondamentale consiste nella definizione di

un automa (che di fatto sarà poi “trasferito” nellatabella di parsing), detto automa LR(0).

◮ Data G (la grammatica) si procede innanzituttoinserendo una produzione aggiuntiva, S ′ → S (il cuisignificato sarà chiaro più avanti).

◮ A partire dalle produzioni, si definiscono poi speciali“oggetti”, che chiameremo item (usando laterminologia standard inglese).

◮ Un item è una produzione con inserito un marcatorenella parte destra, tipicamente un punto.

◮ Ad esempio, gli item associati alla produzioneS → (S)S sono: S → ·(S)S, S → (·S)S, S → (S·)S,S → (S) · S e S → (S)S·.

◮ Ad una produzione tipo S → ǫ è associato il soloitem S → ·.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Automa LR(0) (continua)

◮ Il significato intuitivo di un item associato ad unaproduzione è di indicare in quale punto siamo arrivatinel processo di riconoscimento della parte destradella produzione stessa.

◮ Ad esempio, l’item S → (S) · S indica che abbiamoriconosciuto una stringa descritta da (S) e che“speriamo” di riconoscere successivamente unastringa descrivibile da S.

◮ Gli item vengono poi raggruppati in insiemi (gruppi ocollezioni) che descrivono essenzialmente le stessesituazioni relative all’avanzamento del processo diparsing.

◮ Gli insiemi di item costituiranno gli stati dell’automa.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Automa LR(0) (continua)

◮ Con riferimento all’item S → (S) · S, se siamo alpunto da esso descritto (cioè, in particolare, al puntoin cui speriamo di vedere una stringa descrivibile daS) possiamo dire di essere anche al punto descrittodai seguenti due item: → ·(S)S e S → ·.

◮ Questo naturalmente perché il non terminale S (chesperiamo di vedere) può assumere le due forme(S)S e ǫ.

◮ Si noti che l’intersezione di due collezioni può nonessere vuota.

◮ Ad esempio, l’item S → (·S)S forma gruppo ancoracon S → ·(S)S e S → · (per lo stesso motivo).

◮ Sono le collezioni nel loro insieme che devonoessere distinte.

◮ Si noti che l’item S → (S·)S forma un gruppo da solo.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Per la grammatica “aumentata”

S′ → S

S → (S)S | ǫ

sono definiti i seguenti insiemi di item:

I0 : S′ → ·S I3 : S → (S·)SS → ·(S)SS → · I4 : S → (S) · S

S → ·(S)SI1 : S′ → S· S → ·

I2 : S → (·S)S I5 : S → (S)S·S → ·(S)SS → ·

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Come costruire gli insiemi LR(0)◮ Diamo ora una descrizione dettagliata del

procedimento di costruzione degli insiemi di item.◮ L’insieme iniziale (che indicheremo sempre con I0)

contiene l’item S ′ → ·S e tutti gli item ottenuti dalleproduzioni di S inserendo il punto all’inizio.

◮ Nell’esempio appena considerato, si aggiungono aS′ → ·S due soli item (perché ci sono due produzionirelative ad S).

◮ Si procede poi iterativamente, lavorando ad ognipasso su un insieme Ij già formato.

◮ Si considerano tutti i simboli della grammaticaimmediatamente alla destra del punto in item di Ij .

◮ Per ogni simbolo così individuato, si forma un gruppoIk che contiene, inizialmente, gli item ottenutispostando il punto alla destra del simboloconsiderato.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Come costruire gli insiemi LR(0) (continua)

◮ Ad esempio, fra gli item di I0 (per la grammaticaappena considerata) ci sono due soli simboli alladestra del punto, S e ( . Per ognuno di essi si creanodue nuovi insiemi, I1 e I2, che contengonoinizialmente un solo item ciascuno, S′ → S· in I1 eS → (·S)S in I2.

◮ Tornando alla descrizione generale, se il nuovoinsieme Ik appena inizializzato contiene item in cui ilpunto precede un simbolo non terminale A , siaggiungono ad Ik tutti gli item ottenuti dalleproduzioni di A inserendo il punto all’inizio.

◮ Quest’ultima operazione, che abbiamo già visto piùvolte, è detta chiusura dell’insieme Ik .

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Come costruire gli insiemi LR(0) (continua)

◮ Ad esempio, ad I2 l’operazione di chiusura aggiungegli item S → ·(S)S e S → ·.

◮ Ad I1 invece non viene aggiunto nulla, perché l’unicoitem iniziale (S′ → S·) non ha simboli non terminaliimmediatamente a destra del punto.

◮ Se Ik non coincide con nessuno degli insiemi giàgenerati viene tenuto, altrimenti viene scartato.

◮ Il procedimento si arresta quando non ci sono piùinsiemi di item da considerare.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Consideriamo la seguente grammatica (aumentata)che genera il linguaggio {anbn|n ≥ 1}:

S′ → S

S → aSb | ab

◮ L’insieme iniziale di item è:◮ I0 = {S′ → ·S, S → ·aSb, S → ·ab}.

◮ I simboli immediatamente a destra del punto in I0sono S e a, per cui inizializziamo due insiemi:

◮ I1 = {S′ → S·};◮ I2 = {S → a · Sb, S → a · b}.

◮ La chiusura non aggiunge nulla a I1 (poiché l’itemS′ → ·S ha un non terminale immediatamente adestra del punto), mentre aggiunge item ad I2, chediventa

◮ I2 = {S → a · Sb, S → a · b, S → ·aSb, S → ·ab}.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)

◮ L’insieme non dà origine ad altri insiemi di item(perché non ci sono simboli a destra del punto).

◮ Nel’insieme I2 ci sono tre simboli distinti a destra delpunto, per cui formiamo tre insiemi:

◮ I3 = {S → aS · b};◮ I4 = {S → ab·};◮ I5 = {S → a · Sb, S → a · b}.

◮ La chiusura modifica solo I5, che diviene◮ I5 = {S → a · Sb, S → a · b, S → ·aSb, S → ·ab},

ma che viene scartato in quanto coincidente con I2.◮ Infine lavorando su I3 si ottiene:

◮ I5 = {S → aSb·},

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)

◮ Ricapitolando, gli insiemi LR(0) di item associati allagrammatica sono:

I0 : S′ → ·S I3 : S → aS · bS → ·aSbS → ·ab I4 : S → ab·

I1 : S′ → S· I5 : S → aSb·

I2 : S → a · SbS → a · bS → ·aSbS → ·ab

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Funzioni CLOSURE e GOTO

◮ Il prodedimento appena descritto (in manieraalquanto discorsiva) può essere sinteticamentericapitolato facendo uso delle due funzioniCLOSURE e GOTO, che lavorano su insiemi di item.

◮ Dato un insieme di item I, CLOSURE(I) coincide conl’insieme I cui siano stati aggiunti tutti gli item del tipoB → ·β (dove B → β è una produzione dellagrammatica) qualora almeno un item di X sia del tipoA→ α · Bγ.

◮ Se I è un insieme di item e X un simbolo dellagrammatica GOTO(I, X ) è definito come la chiusuradell’insieme J di item del tipo A→ αX · β, doveA→ α · Xβ è in I.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Algorithm 2 Insiemi di item LR(0)

1: C ← {CLOSURE({S ′ → S})}2: repeat3: for each I ∈ C do4: for each X ∈ T ∪N do5: if GOTO(I, X ) 6= {}and GOTO(I, X ) 6∈ C then6: C ← C ∪ {GOTO(I, X )}7: until No new state is added to C

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Da ultimo, consideriamo la costruzione degli insiemidi item LR(0) per la grammatica aumentata

E ′ → E

E → E + T | T

T → T × F | F

F → (E) | id

che, ricordiamo, non è adatta al parsing top-down.◮ Nella slide seguente presentiamo direttamente la

collezione degli insiemi di item ottenuta applicandol’algoritmo 2.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)

I0 : E ′ → ·E I4 : F → (·E) I7 : T → T × ·FE → ·E + T E → ·E + T F → · (E)E → ·T E → ·T F → ·idT → ·T × F T → ·T × FT → ·F T → ·F I8 : E → E ·+TF → · (E) F → · (E) F → (E ·)F → ·id F → ·id

I9 : E → E + T ·I1 : E ′ → E · I5 : F → id· T → T · ×F

E → E ·+TI6 : E → E + ·T I10 : T → T × F ·

I2 : E → T · T → ·T × FT → T · ×F T → ·F I11 : F → (E) ·

F → · (E)I3 : T → F · F → ·id

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Automa LR(0)

◮ Come già anticipato, le collezioni di item LR(0)determinate con la procedura appena descrittacostituiscono gli stati dell’automa LR(0) (che, a suavolta, è alla base del parsing SLR(1) che stiamocostruendo).

◮ Per completare la descrizione dell’automa ènecessario definire la funzione δ di transizione.

◮ In realtà abbiamo già descritto tale funzione, checoincide “essenzialmente” con la funzione GOTO.

◮ Si noti che, tuttavia, che GOTO(I, X ) “costruisce”nuovi stati e dunque J = GOTO(I, X ) non vieneaggiunto se risulta già definito,

◮ In tale caso vale comunqe δ(I, X ) = J.

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ L’automa LR(0) per la grammatica

S′ → S

S → (S)S | ǫ

è:

I0

I1

I2

I3

I4 I5

accept$S

(

S)

(

(

S

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ L’automa LR(0) per la grammatica

S′ → S

S → aSb | ab

è:

I0

I1

I2

I3

I4

I5

accept$

S

a

a

S

b

b

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio◮ L’ultimo esempio è per la grammatica

E′→ E

E → E + T | T

T → T × F | F

F → (E) | id

I0

I1

I3

I2

I6

I4

I5 I8

I7

I11

I9

I10

accept

$

EF

F

(

+

F

(T

T(

id

id

(

id

+

)

×

×

F

T

id

F

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Tabelle di parsing SLR(1)

◮ Completiamo ora la descrizione del parser conl’algoritmo di definizione della tabella di parsing.

◮ Le tabelle incorporano le informazioni contenutenell’automa, che da sono non è sufficiente pereseguire l’analisi (si ricordi che un automa a statifiniti non è in grado di riconoscere linguaggi liberi(che non siano anche regolari).

◮ L’algoritmo esamina gli stati dell’automa e letransizioni uscendi da ciascuno stato.

◮ Esso necessita anche di conoscere, per ogni simbolonon terminale A, l’insieme di simboli FOLLOW (A).

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Tabelle di parsing SLR(1) (continua)◮ Per ogni stato Ij , consideriamo le transizioni uscenti.◮ Se esiste una transizione da Ij a Ik etichettata X ∈ T

poniamo ACTION [j , X ] = shift k .◮ Se esiste una transizione etichettata X ∈ N poniamo

GOTO [j , X ] = shift X .◮ Se nell’insieme di item corrispondenti a Ij esiste un

item A→ α·, allora poniamoACTION [j , X ] = reduce A→ α per tutti i simboli X inFOLLOW (A).

◮ Se Ij contiene l’item S ′ → S· si poneACTION[i , $] = accept.

◮ Se, ad un qualunque passo dell’algoritmo, simanifesta un cosiddetto conflitto shft-reduce (cioè sitenta di inserire in una entry della parte ACTION siaun’azione di shift che una di riduzione) allora lagrammatica non è SLR(1).

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio

◮ Per la grammaticaS → aSb Produzione 1S → ab Produzione 2

l’algoritmo appena delineato produce la seguentetabella:

StatoACTION GOTO

a b $ S0 shift 2 11 accept2 shift 2 shift 4 33 shift 54 reduce 2 reduce 25 reduce 1 reduce 1

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)

◮ Consideriamo il comportamento del parser su inputaabb

Stack Input Azione$0 aabb$ shift 2$02 abb$ shift 2$022 bb$ shift 4$0224 b$ reduce S → ab$023 b$ shift 5$0235 $ reduce S → aSb$01 $ accept

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio◮ Diamo infine la tabella di parsing per la grammatica

E → E + T Prod. 1 T → F Prod. 4E → T Prod. 2 F → (E) Prod. 5T → T × F Prod. 3 F → id Prod. 6

StatoACTION GOTO

id + × ( ) $ E T F0 s 5 s 4 1 2 31 s 6 accept2 r 2 s 7 r 2 r 23 r 4 r 4 r 4 r 44 s 5 s 4 8 2 35 r 6 r 6 r 6 r 66 s 5 s 4 9 37 s 5 s 4 108 s 6 s 119 r 1 s 7 r 1 r 110 r 3 r 3 r 3 r 311 r 5 r 5 r 5 r 5

LFC

Parsing dilinguaggi liberiIntroduzione

Parsing top-down

Parsing bottom-up

Esempio (continua)◮ Consideriamo il comportamento del parser su input

id× (id + id)

Stack Input Azione$0 id × (id + id) $ shift 5$0 5 × (id + id) $ reduce F → id$0 3 × (id + id) $ reduce T → F$0 2 × (id + id) $ shift 7$0 2 7 (id + id) $ shift 4$0 2 7 4 id + id) $ shift 5$0 2 7 4 5 +id) $ reduce F → id$0 2 7 4 3 +id) $ reduce T → F$0 2 7 4 2 +id) $ reduce E → T$0 2 7 4 8 +id) $ shift 6$0 2 7 4 8 6 id) $ shift 5$0 2 7 4 8 6 5 ) $ reduce F → id$0 2 7 4 8 6 3 ) $ reduce T → F$0 2 7 4 8 6 9 ) $ reduce E → E + T$0 2 7 4 8 ) $ shift 11$0 2 7 4 8 11 $ reduce F → (E)$0 2 7 10 $ reduce T → T × F$0 2 $ reduce E → T$0 1 $ accept