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