Gramatyki i parsery SLR(1)

Transkrypt

Gramatyki i parsery SLR(1)
Gramatyki i parsery SLR(1)
GLR(0) ⊂ GLR(1)
Wiele gramatyk nie spełnia wymagań LR(0), ale spełnia LR(1) z nadmiarem. Z
drugiej strony, konstrukcja parsera LR(1) jest procesem dość złożonym, a sama
tablica LR(1) zajmuje stosunkowo duży obszar pamięci. Stąd pojawiły się
gramatyki pośrednie SLR oraz LALR.
GLR(0) ⊂ GSLR(1) ⊂ GLALR(1) ⊂ GLR(1)
LR(0) – sytuacja
G = <N, T, P, Z> ∈ GBK(1)
[A → β1 ⋅ β2] - LR(0) sytuacja ⇔! (A → β1 β2 ) ∈ P
LR(0) - sytuacja dopuszczalna
[A → β1 ⋅ β2] - LR(0) sytuacja dopuszczalna dla aktywnego prefiksu αβ ⇔!
*
∃ wywód: Z ⇒αAw ⇒αβ1 β 2 w
R
R
J0 – Kanoniczny system zbiorów LR(0) sytuacji dopuszczalnych
J0 jest zbiorem wszystkich zbiorów I(γ) LR(0) sytuacji dopuszczalnych;
γ - aktywny prefiks w gramatyce G’.
Wyznaczanie kanonicznego systemu zbiorów LR(0) sytuacji podobne jak w
przypadku LR(1). podajemy tylko “funkcje” stanowiące podstawę odpowiednich
algorytmów.
function CLOSURE (I);
begin
J:=I;
repeat
for każda sytuacja [ A → α⋅Bβ] ∈ I do
for każda produkcja ( B → η ) ∈ P do’
I:=I ∪ { [ B → ⋅ η]};
until nic nowego nie dodano do I;
return (I)
end;
function GOTO (I, X);
begin
I:= ;
for każda sytuacja [ A →α . X β ] ∈I do
I:=I ∪{[ A →α . X β ]};
return (CLOSURE(I));
end;
function ITEMS(G’);
begin
Jo:={CLOSURE({Z’→ . Z]})};
repeat
for każdy zbiór I ∈ J0 do
for każdy X ∈ ( N ∪ T ) do
if GOTO (I,X) ≠ then
J0:=J0 ∪ { GOTO ( I , X ) };
until nic nowego nie dodano do J0;
return J0;
end;
Gramatyki SLR(1) /simple LR(1)/
G = <N, T, P, Z> ∈ GBK
J0 – kanoniczny system zbiorów LR(0) sytuacji dopuszczalnych dla G
G jest gramatyką SLR(1)⇔!
[A → α • β ]∈ I 
różne LR(0) sytuacje!
[A → α • β ]∈ I 
∀I ∈ J 0 : ∀
Zachodzi dokładnie jeden z poniższych warunków:
1.)
2.)
3.)
4.)
β≠ε∧δ≠ε
β ≠ ε ∧ δ = ε ∧ β = a β1 ∧ a ∈ T ∧ FOLLOW1(B) ∩ {a} = ∅
β = ε ∧ δ ≠ ε ∧ δ = a δ1 ∧ a ∈ T ∧ FOLLOW1(A) ∩ {a} = ∅
β = ε ∧ δ = ε ∧ FOLLOW1(A) ∩ FOLLOW1(B) = ∅
Algorytm działania parsera SLR(1) jest identyczny jak LR(1). Inny jest sposób
tworzenia tablicy parsera.
Konstrukcja tablicy parsera SLR(1)
We: G’ - gramatyka uzupełniona dla gramatyki bezkontekstowej G.
Wy: Tablica parsera SLR(1) - funkcje f i g
Metoda:
1.) Konstruujemy J0 - kanoniczny system zbiorów, LR(0) sytuacji
dopuszczalnych dla G’.
2.) Numerujemy produkcje gramatyki G’.
3.) for każdy zbiór Ij ∈ J0 do
begin
(a)
utwórz w tablicy parsera stan Tj∈τ dla analizowanego Ij ∈ J0;
for każda sytuacja ze zbioru Ij do
begin
if [ A →α . a β ] ∈ Ij and a∈T and GOTO(Ij , a) = Ik
then f(Tj,a) := shift-k
(b)
if [ A →α . ] ∈ Ij and A≠Z’ and i - numer produkcji
(A →α )∈P then for każdy a∈FOLLOW1(a) do
f(Tj,a) := red-1;
(c)
if [ Z’ →Z. ] ∈ Ij then f(Tj,$) := acc;
end;
for każdy A ∈ N do
if GOTO (Ij,A) ≠ ∅ and GOTO (Ij,A) = Ik then g(Tj,A) := Tk;
end;
if w jakiejkolwiek pozycji tablicy parsera SLR(1) jest więcej niż jeden zapis then
STOP; /* gramatyka nie jest SLR(1) */
1.) for każdy Tj∈τ do
begin
for każdy a∈T∪{$} do
if f(Tj,a) nieokreślone then f(Tj,a) :=err;
for każdy A∈N do
if g(Tj,A) nieokreślone then g(Tj,A) := err;
end;
1.) Stanem początkowym parsera jest ten stan, który odpowiada zbiorowi I ∈ J0 ,
dla którego [ Z’ →Z. ] ∈ Ij ;
Przykład: konstrukcja tablicy SLR(1)dla gramatyki G’:
G’ = <N’ = {E’,E,T,F}, T = {+,*,(,),id}, P’, Z’ = E’> /* gramatyka uzupełniona */
P’ = {0. E’ → E
1. E → E + T
2. E → T
3. T → T * F
4. T → F
5. F → ( E )
6. F → id
}
konstrukcja zbioru Jo
A0 =
{[E’ → .E],
[E → .E+T],
[E → .T],
[E → T*F],
[E → .F],
[E → .(E)],
[E → .id]
}
A1 = {[E’ → E.],
[E → E.+T],
}
A2 = {[E → T.],
[T → T.*F],
}
A3 = {[T → F. ] }
A4 = {[F → (.E)],
[E → .E+T]
[E → .T]
[T → .T*F]
[T → .F]
[F → .(E)]
[F → id]
}
A5 = {[F → id.]}
A1 = GOTO(A0,E)
A2 = GOTO(A0,T)
A3 = GOTO(A0,F)
GOTO(A0 , +|*|) ) = ∅
A4=GOTO(A0,( )
A5=GOTO(A0,id)
A6 = {[E → E + .T],
[T → .T*F],
[T → .F],
[F → .(E)],
[F → .id],
}
A7 = {[T → T*.F],
[F → .(E)],
[F → .id],
}
A8 = {[F → (E.)],
[E → E.+T],
}
A9 = {[E → E+T.],
[T → T.*F]}
A10={[T → T*F.]}
A11={[F → (E).]}
FIRST1 (E) = { (, id }
FIRST1 (T) = { (, id }
FIRST1 (F) = { (, id }
FOLLOW1 (E’) = { $ }
A6=GOTO(A1,+)
GOTO(A1, E|T|F|*|(|)|id )= ∅
A7=GOTO(A2,*)
GOTO(A2, E|T|F|+|(|)|id )= ∅
GOTO(A3, E|T|F|+|*|(|)|id )= ∅
A8=GOTO(A4,E)
A2=GOTO(A4,T)
A3=GOTO(A4,F)
A4=GOTO(A4,()
A5=GOTO(A4,id)
GOTO(A4, +|*|) )= ∅
GOTO (A5, E|T|F|+|*|(|)|id)= ∅
A9=GOTO(A6,T)
A3=GOTO(A6,F)
A4=GOTO(A6,()
A5=GOTO(A6,id)
GOTO(A6, E|+|*|) )= ∅
A10=GOTO(A7,F)
A4=GOTO(A7,()
A5=GOTO(A7,id)
GOTO(A7, E|T|+|*|) )= ∅
A11=GOTO(A8,))
A6=GOTO(A8,+)
GOTO(A8, E|T|F|*|(|id )= ∅
A7=GOTO(A9,*)
GOTO(A9, E|T|F|+|(|)|id )= ∅
GOTO(A10, E|T|F|+|*|(|)|id )= ∅
GOTO(A11, E|T|F|+|*|(|)|id )= ∅
FOLLOW1 (E) = { $,+,) }
FOLLOW1 (T) = { $,+,*,) }
FOLLOW1 (F) = { $,+,*,) }
tablica SLR(1)
stan
f
$
T0
T1
T2
T3
T4
T5
T6
T7
T8
T9
T10
T11
+
*
(
)
shift4
acc
red-2
red-4
shift 6
red-2
red-4
shift
red-4
id
E
g
T
shift5
T1
T2
T3
T8
T2
T3
T9
T3
T10
red-2
red-4
shift4
red-6
red-6
red-6
red-6
shift4
shift4
red-1
red-3
red-5
shift6
red-1
red-3
red-5
shift7
red-3
red-5
F
shift5
shift5
shift11
red-1
red-3
red-5
Kratki puste = err !
Przykład: eliminacja niejednoznaczności gramatyki nie będącej gramatyką
SLR(1) - konstrukcja parsera SLR(1) dla gramatyki niejednoznacznej
Rozważana gramatyka:
(0) E’ → E
(1) E → E + E
(2) E → E *E
(3) E → ( E )
(4) E → id
jest uproszczoną, a zarazem niejednoznaczną
wersją gramatyki SLR(1) z poprzedniego
przykładu:
(0) E’ → E
(1) E → E + T
(3) T → T * F
(5) F → ( E )
(6) F → id
(*)
(2) E → T
(4) T → F
(*) W rozważanej gramatyce nie ma produkcji łańcuchowych, więc gdyby udało
się skonstruować dla niej parser SLR(1) to rozbiór syntaktyczny byłby jeszcze
szybszy, a także rozmiar tablicy parsera byłby mniejszy.
1.) Konstruujemy system zbiorów LR(0) - sytuacji
2.) Próbując zbudować tablicę dla parsera SLR(1) znajdujemy konflikty
3.) Staramy się usunąć konflikty wykorzystując dodatkowe wiadomości i
wymagania związane z językiem generowanych przez rozważaną
gramatykę niejednoznaczną.
A0:
E’ → .E
E → . E+E
E → . E*E
E → . (E)
E → . id
A6:
E → (E.)
E → E. + E
E → E. * E
A1:
E’ → E.
E → E.+E
E → E.*E
A2:
E → (. E )
E → . E+E
E → . E*E
E → . (E)
E → . id
A3:
E → id.
A4:
E → E+.E
E → .E+E
E → .E*E
E → .( E )
E → .id
A5:
E → E*.E
E → .E+E
E → .E*E
E → .(E)
E → .id
E → E+E.
E → E.+E
E → E.*E
KONFLIKTY!
A8: E → E*E.
E → E.+E
E → E.*E
KONFLIKTY!
A9: E → (E).
Konflikty dla A7:
a) ponieważ:{ + , * } ⊂ FOLLOW1(E)
więc:
f (T7 , + ) = red 1
f (T7 , * ) = red 1
b) ponieważ ponieważ:{ + , * } ⊂ T
więc:
f (T7 , + ) = shift
f (T7 , * ) = shift
A7:
Konflikty:
f (T7 , + ) = red 2
f (T7 , * ) = red 2
f (T7 , + ) = shift
f (T7 , * ) = shift
Podobne konflikty dla A8
f (T8 , + ) = red 2 f (T8 , + ) = shift
f (T8 , * ) = red 2 f (T8 , * ) = shift
Rozważamy ciąg wejściowy: id+id*id
Ponieważ “*” ma wyższy priorytet niż “+”, więc “*” powinna być wcześniej
redukowana niż “+”
Stos:
T0ET1+T4ET7
we:
* id
DECYZJA: f(T7, *) = shift
E
E + E
później
E * E
id id
wcześniej
id
Rozważamy ciąg wejściowy : id * id + id
Ponieważ “+” jest lewostronnie łączny , więc najpierw powinna nastąpić redukcja
lewego “+”
Stos:
T0ET1+T4ET7
we:
+ id
E
E + E
DECYZJA: f(T7, +) = red 1
E * E
id
id id
Podobnie rozstrzygamy konflikty dla A8:
id*id ↓ * id ⇒ lewa łączność “*” ⇒ f(T8,*) = red 2
T8
id*id ↑ + id ⇒ wyższy priorytet “*” ⇒ f(T8,+) = red 2
Tablica parsera SLR(1) dla niejednoznacznej gramatyki
id
+
*
(
)
$
E
T0
shift 3
shift 2
T1
T1
shift 4 shift 5
acc
T2
shift 3
shift 2
T6
T3
red 4 red 4
red 4 red 4
T4
shift 3
shift 2
T7
T5
shift 3
shift 2
T8
T6
shift 4 shift 5
shift 9
red 1 red 1
T7
red 1 shift 5
red 2 red 2
T8
red 2 red 2
T9
red 3 red 3
red 3 red 3
później
wcześniej