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