Costruzione dell`insieme dei Follow
Transcript
Costruzione dell`insieme dei Follow
Costruzione dell’insieme dei Follow E ! T E’ | - T E’ E’ ! + T E’ | - T E’ | " T ! F T’ T’ ! *F T’ | " F ! (E) | i Per evitare che alcuni insiemi siano vuoti si aggiunge per default il simbolo speciale $ che demarca la fine della stringa da esaminare Siccome l’insieme dei FOLLOW(Y) comprende tutti i simboli terminali t che possono seguire immediatamente Y ovvero S #+ u Y t v si ha: FOLLOW (E) = { $, )} FOLLOW (E’) = { $, )} FOLLOW (T) = { $, ),- , +} FOLLOW (T’) = { $, ). -, +} FOLLOW (F) = { $, ). -, +, *} per esempio: E # T E’ # F T’ E’ # F * F T’E’ #F*FT’ # F*F # ( E ) *F # (T E’) * F # ( T ) *F #.... # Costruzione dell’insieme dei Follow cont. E ! T E’ | - T E’ E’ ! + T E’ | - T E’ | " T ! F T’ T’ ! *F T’ | " F ! (E) | i Si considera il grafo dell’insieme dei FIRST prima costruito, si aggiungono ulteriori nodi per i soli simboli non terminali (questi ultimi vengono indicati con un doppio rettangolo sul grafo e con X nelle regole seguenti). R1 -Si traccia l’arco S ! $ per il simbolo iniziale S R2 -Per ogni regola W ! u X t v si traccia l’arco X ! t R2 R3 -Per ogni regola W ! u X si traccia l’arco X ! W E R4 -Per ogni regola W ! u X Y1 , Y2 ..... Yn con Y1 , Y2 ..... Yn #+ " Si tracciano gli archi X !W , X! Y1 .... X! Yn R3 E’ R4 Tutti i simboli terminali raggiungibili a partire da un simbolo non terminale X fanno parte del FOLLOW di X, pertanto: FOLLOW (E) = { $, )} FOLLOW (E’) = { $, )} FOLLOW (T) = { $, ),- , +} FOLLOW (T’) = { $, ). -, +} FOLLOW (F) = { $, ). -, +, *} ) R1 $ R4 R4 T E’ R3 R4 + - T’ R4 F T’ * R4 Si osservi come per motivi grafici non è stata indicata una parte del grafo dei FIRST in quanto non funzionale per il risultato finale (nodi del grafo dei FIRST non raggiungibili). Condizioni LL(1) Una grammatica si dice LL(1) se per ogni regola !! X ! x1 | x2 | ...... | xn xi " V* sono soddisfatte le seguenti condizioni 1. FIRST (xi) sono a due a due disgiunti 2. Esiste al più un solo xi #* $ e se esiste deve verificarsi !! FIRST(X) % FOLLOW (X) = & Condizioni LL(1) cont. 1. FIRST (xi) sono a due a due disgiunti ! ciò significa che dato un non terminale X non devono esistere due derivazioni ! S !* u X v ! u " v !* u z v ! S !* u X v’ ! u "’ v’ !* u z’ v’ in cui " # "’ e i primi caratteri di z v e z’v’ coincidono cioè !! FIRST (zv) = FIRST (z’v’) oppure z v = z’v’ = $ Es. la regola ricorsiva a sinistra E % E + T | T viola la condizione 1. ! ! E ! E+T!T+T!* i +i E ! E+T!E+ T+T!* i + i + i mentre invece con E % T E’ E’% +T E’ | $ Infatti FIRST (i+i ) = FIRST (i+i+i) e nella sequenza si ha che " # "’ !! si avrebbe ! E ! TE’!T+ TE’!T+T!* i +i ! E ! TE’!T+ TE’!T+T+TE’!* i + i + i anche in questo caso FIRST (zv) = FIRST (z’v’) ma in ogni momento " = "’ Condizioni LL(1) cont. 2. Esiste al più un solo xi !* " e se esiste deve verificarsi FIRST(X) # FOLLOW (X) = $ Es. ! S % if E then S S’ | a | b ! ! S’% else S | " dove a, b sono espressioni aritmetiche o booleane p, q sono espressioni booleane & E%p|q siccome: ! FIRST(S) = {if, a, b}, FIRST (S’) = {else}, FIRST (E) ={ p, q } !! FOLLOW(S) = {else, $}, FOLLOW(S’) ={else, $} , FOLLOW(E) ={then} si ha che S’! ", ma gli insiemi FIRST(S’) # FOLLOW(S’) '$ per cui la grammatica è ambigua Esercizio 1 data l’espressione if p then if q then a else b costruire i due alberi sintattici relativi e dire quale albero corrisponde all’interpretazione corretta. Esercizio 2 Scrivere una grammatica non ambigua equivalente a quella data. Analizzatori sintattici a discesa ricorsiva E’ uno schema di analizzatore che sfrutta la descrizione grammaticale in EBNF adatto a grammatiche LL(1). Si basa sulla scrittura di procedure ricorsive ricavate direttamente dalle regole grammaticali. IDEA Ogni produzione viene interpretata come una procedura in cui la parte sinistra rappresenta il nome e la parte destra la definizione (corpo) della procedura. Lo stack risulta implementato implicitamente dal meccanismo di implementazione delle chiamate ricorsive. Data una generica regola X ! x1 | x2 | ...... | xn ! si distinguono due possibili strutture della procedura a seconda di quale delle due condizioni si verifichi 1. X# + " Cioé la variabile non genera " 2. X #+ " Cioé la variabile genera " Inoltre, si deve supporre l’esistenza di una routine che rende disponibile i caratteri che via via vengono scanditi. Questa routine in genere è associata ad un analizzatore lessicale. Analizzatori lessicali Un analizzatore lessicale ha il compito di esaminare carattere per carattere la stringa in ingresso e produrre una forma standard degli item di volta in volta individuati. Tipicamente gli analizzatori lessicali vengono implementati con automi a stati finiti. Esempio: procedure somma (var S:integer); !var i:integer; ! begin ! S:=0; ! for i:=1 to 10 do S:= S + i * 500; end; procedure somma ( var S : integer ) ; var i : integer ; begin ! S := 0 ; for i := 1 to 10 do S := S + i * 500 ; end ; In pratica l’analizzatore lessicale ha il compito di categorizzare le varie stringhe selezionate in modo che ciascuna stringa rappresenti un unico item. Ad esempio: alfa + pigreco * gamma è come dire i +i*i Al momento dell’analisi sintattica interessa la struttura di una espressione e quindi la tipologia degli operandi indicati. Analizzatori sintattici a discesa ricorsiva 1. X # + " ! procedure X; ! begin !! if cc in FIRST(x1) then {codice di x1 } !! else if cc in FIRST(x2) then {codice di x2 } $ ! $ $ !! !! ! ! ...... $ else if cc in FIRST(xn) then {codice di xn } else ERRORE end; 2. X #+ " procedure X; ! begin! if cc in FIRST(x1) then {codice di x1 } !! else if cc in FIRST(x2) then {codice di x2 } !! ! ! !! ! ...... else if cc in FIRST(x ) then {codice di x } n n else if not [ cc in FOLLOW(X)] then ERRORE end; - cc = carattere corrente - per l’ipotesi FIRST(xi)% FIRST(xj) = & viene attivata una sola parte destra