3.4. Przekształcenia gramatyk bezkontekstowych
Transkrypt
3.4. Przekształcenia gramatyk bezkontekstowych
3.4. Przekształcenia gramatyk bezkontekstowych Definicje Niech będzie dana gramatyka bezkontekstowa G = <N, T, P, Z> ∈ GBK Symbol X ∈ (N∪T) nazywamy nieużytecznym w G∈GBK jeśli nie można w tej gramatyce przeprowadzić wyprowadzenia: Z ⇒*G wXy ⇒*G wxy przy czym w,x,y ∈ T* (czyli z X nie można wyprowadzić żadnego słowa w symbolach terminalnych). Symbol X ∈ (N∪T) nazywamy nieosiągalnym w G∈GBK, jeśli X nie pojawia się w żadnej formie zdaniowej tej gramatyki (czyli nie można go wyprowadzić z Z). Gramatyka G∈GBK jest gramatyką bez ε-produkcji, gdy: (i) P nie zawiera produkcji postaci A→ε, A∈N, A≠Z (ii) jeśli (Z→ε) ∈ P to symbol Z nie występuje w prawych stronach pozostałych produkcji Twierdzenie 3.4.1. Każdą gramatykę bezkontekstową G = <N, T, P, Z> ∈ GBK można przekształcić do postaci równoważnej G’ = <N’, T’, P’, Z> ∈ GBK (to znaczy takiej, że L(G’) = L(G) ) nie zawierającej symboli nieosiągalnych, symboli nieużytecznych oraz będącej gramatyką bez εprodukcji (w sensie powyższych definicji). Sposoby wykonania odpowiednich przekształceń podają poniższe algorytmy. Czytelnik zechce udowodnić poprawność tych algorytmów. Algorytm usuwania symboli nieosiągalnych wejście: G = <N, T, P, Z> ∈ GBK wyjście: G’ = <N’, T’, P’, Z> ∈ GBK taka, że (i) L(G’) = L(G) (ii) ( ∀ X∈(N’∪T’) ) ( ∃ α,β∈(N’∪T’)* ) ( Z ⇒*G’ αXβ ) Metoda: V0 := {Z}; i := 0; repeat i := i + 1; Vi := Vi-1 ∪ {X ∈ (N∪T) | (A→αXβ) ∈ P ∧ A ∈ Vi-1 ∧ α,β ∈ (N∪T)* }; until Vi = Vi-1 ; /* Vi zawiera te symbole terminalne i nieterminalne które: - występują w produkcjach z P - dają się wyprowadzić z Z */ N’ := Vi ∩ N; T’ := Vi ∩ T; P’ := {(u→v) ∈ P | u,v ∈ V*i } /* zawiera te produkcje z P, które zbudowane są z symboli z Vi */ G’ := <N’, T’, P’, Z> Algorytm usuwania symboli nieużytecznych wejście: G = <N, T, P, Z> ∈ GBK wyjście: G’ = <N’ , T’, P’, Z> ∈ GBK taka, że: (i) L(G’) = L(G) (ii) (N’∪T’) nie zawiera symboli nieużytecznych Metoda: N0 := φ; /* φ - zbiór pusty */ i := 0; repeat i := i + 1; Ni := Ni-1 ∪ { A ∈ N | (A→α) ∈ P ∧ α ∈ (Ni-1∪T)* } until Ni = Ni-1; G1 := < N ∩ Ni , T, P1 , Z> gdzie P1 := {(u→v) ∈ P | u,v ∈ (Ni∪T)* }; zastosować do G1 algorytm usuwania symboli nieosiągalnych uzyskując w wyniku tego gramatykę G’ = <N’, T’, P’, Z> Przykład: G = <{S, A, B}, {a, b}, {S→a ; S→A ; A→AB ; B→b}, S> G1 = <{S, B}, {a, b}, {S→a ; B→b}, S> G’ = <{S}, {a}, {S→a}, S> Algorytm usuwania ε-produkcji wejście: G = <N, T, P, Z> ∈ GBK wyjście: G’ = <N’, T, P’, Z’> ∈ GBK taka, że: (i) L(G) = L(G’) (ii) G’ jest gramatyką bez ε-produkcji Metoda: N0 := φ; /* φ - zbiór pusty */ i := 0; repeat i:= i + 1; Ni := Ni-1 ∪ { A ∈ N | (A→x) ∈ P ∧ x ∈ Ni-1* }; until Ni = Ni-1; Ne := Ni ; /* Ne = {A | A ∈ N ∧ A ⇒+G ε} */ P’ := P ; for (A→x) ∈ P do begin przedstawiamy „x” w postaci α0B1α1B2α2 ... Bkαk, k ≥ 0, gdzie Bi ∈ Ne (1 ≤ i ≤ k), αi ∈ ((N∪T) – Ne)* (0 ≤ i ≤ k); P’ := P’ ∪ {(A → α0X1α1X2α2 ... Xkαk) : (Xi= Bi ∨ Xi = ε)}; if (A→ε) ∈ P’ then P’ := P’ – {(A→ε)}; end; if Z ∈ Ne then begin N’ := N ∪ {Z’}; P’ := P’ ∪ {(Z’ → Z), (Z’ → ε)}; Z’ := Z’; end else begin N’ := N; Z’ := Z; end; Przykład: S → aSbS S → bSaS S→ε Po usunięciu S → ε otrzymujemy S’ → S S’ → ε S → aSbS , S → aSb , S → abS , S → ab S → bSaS , S → bSa , S → baS , S → ba Usuwanie produkcji łańcuchowych i cykli Produkcje łańcuchowe, to produkcje postaci: A → B ; A, B ∈ N Gramatyka G zawiera cykle, wówczas gdy istnieją w gramatyce wyprowadzenia postaci A ⇒+G A ; A ∈ N Cykle typu A ⇒+ A powstają poprzez istnienie w gramatyce produkcji łańcuchowych, np. A → B, B → C, C → A, więc usuwając produkcje łańcuchowe – usuwamy również automatycznie wszystkie cykle. Twierdzenie 3.4.2. Każdą gramatykę bezkontekstową G = <N, T, P, Z> ∈ GBK można przekształcić do postaci równoważnej G’ = <N’, T’, P’, Z> ∈ GBK (to znaczy takiej, że L(G’) = L(G) ) nie zawierającej produkcji łańcuchowych i cykli (w sensie powyższych definicji). Algorytm usuwania produkcji łańcuchowych i cykli wejście: G = <N, T, P, Z> ∈ GBK ; G – bez ε-produkcji! wyjście: G’ = <N, T, P’, Z> ∈ GBK taka, że (i) L(G) = L(G’) (ii) G’ – nie zawiera produkcji łańcuchowych i cykli Metoda: for A ∈ N do begin N0 := {A}; i := 0; repeat i := i + 1; Ni := Ni-1 ∪ { C ∈ N | (B → C) ∈ P ∧ B ∈ Ni-1 } until Ni-1 = Ni ; NA := Ni ; /* NA = { B | A ⇒+G B } */ end; P’ := φ; /* φ - zbiór pusty */ for p ∈ P do begin if p = (B → α) and α ∉ N then begin MB := {A ∈ N | B ∈ NA}; /* p nie jest łańcuchowa */ /* MB = { A : A ⇒*G B} */ for A ∈ MB do P’ := P’ ∪ { A → α }; end; end; Przykład: Rozpatrujemy gramatykę: (1) E→E+T (2) E→T (3) T→T*F (4) T→F (5) F→(E) (6) F → id Wyznaczamy odpowiednie zbiory nieterminali: NE = { E, T, F } NT = { T, F } NF = { F } ME = { E } MT = { E, T } MF = { E, T, F } Analizujemy kolejno wszystkie produkcje gramatyki przekształcanej (1) E→E+T (2) wypada, bo jest łańcuchowa (3) E→T*F (4) wypada, bo jest łańcuchowa (5) E→(E) T→(E) F→(E) (6) E → id T → id F → id T→T*F Definicja Gramatyka G = < N, T, P, Z > ∈ GBK nazywa się prawidłową, jeśli: (i) nie zawiera cykli, (ii) jest gramatyką bez ε-produkcji, (iii) nie zawiera nieużytecznych symboli. Usuwanie lewostronnej rekursji U ∈ N jest symbolem lewostronnie rekursywnym gramatyki G jeżeli U ⇒+G Uβ ; β ∈(N∪T)* Gramatyka G nazywa się lewostronnie rekursywną ⇔ (∃ U∈N) ( U ⇒+G Uβ ; β ∈ (N∪T)* ) Twierdzenie 3.4.3. Dana jest gramatyka G = < N, T, P, Z > ∈ GBK oraz symbol nieterminalny A ∈ N. Zbiór { A → Aα1 | ... | Aαm | β1 | ... | βn } ⊆ P jest zbiorem wszystkich produkcji mających po lewej stronie symbol A ; żadne z βi ∈ (N∪T)* (i = 1, ... , n) nie zaczyna się od symbolu A. Niech G’ = < N ∪ {A’}, T, P’, Z > będzie nową gramatyką, w której A’ – nowy symbol nieterminalny zaś zbiór produkcji P' jest określony jak niżej P’ = P – {A → Aα1 | ... | Aαm | β1 | ... | βn } ∪ { A → β1A’ | ... | βnA’ } ∪ { A’ → α1A’ | ... | αmA’ | ε } Wówczas zachodzi L(G) = L(G’). Twierdzenie podaje sposób usuwania lewej rekursji, ale tylko bezpośredniej. Przykład: A → Aα A A→β Analizowane słowo : βααα α A α A A α β Po modyfikacji: A → βA’ A’ → ε A’ → αA’ Analizowane słowo : βααα A β A’ α A’ α A’ α A’ ε Twierdzenie 3.4.4. Każdą gramatykę bezkontekstową G = <N, T, P, Z> ∈ GBK można przekształcić do postaci równoważnej G’ = <N’, T’, P’, Z> ∈ GBK (to znaczy takiej, że L(G’) = L(G) ) nie zawierającej (bezpośredniej i pośredniej) lewostronnej rekursji. Algorytm usuwania (także pośredniej) rekursji lewostronnej wejście: G = <N, T, P, Z> ∈ GBK , G –gramatyka prawidłowa! wyjście: G’ = <N’, T, P’, Z> ∈ GBK taka, że (i) G’ – nie jest gramatyką lewostronnie rekursywną (ii) L(G’) = L(G) Metoda: numerujemy symbole nieterminalne ⇔ N := {A1, ... , An}; n := #N N’ := N ; P’ := P ; i := 1 ; repeat if ∃(Ai → Aiδ) ∈ P’ and δ ∈ (N∪T)* then begin N’ := N’ ∪ {Ai’} P’ := P’ – {Ai → Aiα1 | ... | Aiαq | β1 | ... | βp} ∪ {Ai → β1Ai’ | ... | βpAi’} ∪ {Ai’ → α1Ai’ | ... | αqAi’ | ε} end; /* q – liczba wszystkich produkcji Ai → Ai ... (lewostr. rekurs.) żadne z β1, ... , βp nie zaczyna się od Ai p – liczba wszystkich produkcji Ai → ... bez lewej rekursji */ if i = n then STOP else i := i + 1 ; for j := 1 to i –1 do P’ := P’ – {Ai → Ajα1 | ... | Ajαx} ∪ { (Ai → γkαl ) | l = 1, ... , x k = 1, ... , m γk – prawe strony produkcji: Aj → γ1 | ... | γk | ... | γm}; /* x – liczba wszystkich produkcji typu Ai → Ajα m – liczba wszystkich produkcji typu Aj → γ1 | ... | γm */ until FALSE ; /* w ten sposób prawa strona każdej produkcji Ai → ... zaczyna się albo od symbolu terminalnego, albo od nieterminala Aj o numerze j > i */ Przykład: A → BC | a B → CA | Ab C → AB | CC | a Rodzaje rekursji lewostronnej: 1 2 A A C B 3 B C rekursja posrednia I i=1 G bez zmian II i=2;j=1 B → CA | BCb | ab I i=2 B → CAB’ | abB’ B’ → CbB’ | ε II I i=3;j=1 C → BCB | aB | CC | a i=3;j=2 C → CAB’CB | abB’CB | aB | CC | a i=3 C → abB’CBC’ | aBC’ | aC’ C’ → AB’CBC’ | CC’ | ε Ostatecznie: A → BC | a B → CAB’ | abB’ B’ → CbB’ | ε C → abB’CBC’ | aBC’ | aC’ C’ → AB’CBC’ | CC’ | ε rekursja bezposrednia Wariant drugi usuwania lewostronnej rekursji – dla potrzeb przekształcania gramatyki bezkontekstowej do postaci normalnej Greibacha Twierdzenie 3.4.3. (wariant drugi) Dana jest gramatyka G = < N, T, P, Z > ∈ GBK oraz symbol nieterminalny A ∈ N. Zbiór { A → Aα1 | ... | Aαm | β1 | ... | βn } ⊆ P jest zbiorem wszystkich produkcji mających po lewej stronie symbol A ; żadne z βi ∈ (N∪T)* (i = 1, ... , n) nie zaczyna się od symbolu A. Niech G’ = < N ∪ {A’}, T, P’, Z > będzie nową gramatyką, w której A’ – nowy symbol nieterminalny zaś zbiór produkcji P' jest określony jak niżej P’ = P – {A → Aα1 | ... | Aαm } ∪ { A → β1A’ | ... | βnA’ } ∪ { A’ → α1A’ | ... | αmA’ | α1 | ... | αm } Wówczas zachodzi L(G) = L(G’). Twierdzenie podaje drugi sposób usuwania bezpośredniej lewej rekursji (nie powodujący dodawania ε–produkcji ale zwiększający liczbę nowych produkcji wprowadzanych do gramatyki). Przykład: A → Aα A A→β Analizowane słowo : βααα α A α A A α β Po modyfikacji: A → βA’ A→β A’ → αA’ A' → α Analizowane słowo : βααα A β A’ α A’ α A’ α Drugi wariant algorytmu usuwania (także pośredniej) rekursji lewostronnej wejście: G = <N, T, P, Z> ∈ GBK , G –gramatyka prawidłowa wyjście: G’ = <N’, T, P’, Z> ∈ GBK taka, że (i) G’ – nie jest gramatyką lewostronnie rekursywną (ii) L(G’) = L(G) Metoda: numerujemy symbole nieterminalne ⇔ N := {A1, ... , An}; n := #N N’ := N ; P’ := P ; i := 1 ; repeat if ∃(Ai → Aiδ) ∈ P’ and δ ∈ (N∪T)* then begin N’ := N’ ∪ {Ai’} P’ = P – {Ai → Aiα1 | ... | Aiαq } ∪ {Ai → β1Ai’ | ... | βpAi’} ∪ {Ai’ → α1Ai’ | ... | αqAi’ | α1 | ... | αq } end; /* q – liczba wszystkich produkcji Ai → Aiαr... (lewostr. rekurs.) żadne z β1, ... , βp nie zaczyna się od Ai p – liczba wszystkich produkcji Ai → βr... (bez lewej rekursji) */ if i = n then STOP else i := i + 1 ; for j := 1 to i –1 do P’ := P’ – {Ai → Ajα1 | ... | Ajαx} ∪ { (Ai → γkαl ) | l = 1, ... , x k = 1, ... , m γk – prawe strony produkcji: Aj → γ1 | ... | γk | ... | γm}; /* x – liczba wszystkich produkcji typu Ai → Ajα m – liczba wszystkich produkcji typu Aj → γ1 | ... | γm */ until FALSE ; /* w ten sposób prawa strona każdej produkcji Ai → ... zaczyna się albo od symbolu terminalnego, albo od nieterminala Aj o numerze j > i */ Przykład: A → BC | a B → CA | Ab C → AB | CC | a I i=1 G bez zmian II i=2;j=1 B → CA | BCb | ab I i=2 B → CAB’ | abB’ | CA | ab B’ → CbB’ | Cb II I i=3;j=1 C → BCB | aB | CC | a i=3;j=2 C → CAB’CB | abB’CB | CACB | abCB | aB | CC | a i=3 C → abB'CBC' | abCBC' | aBC' | aC' | abB'CB | abCB | aB | a C’ → AB'CBC' | ACBC' | CC' | AB'CB | ACB | C Ostatecznie: A → BC | a B → CAB’ | abB’ | CA | ab B’ → CbB’ | Cb C → abB'CBC' | abCBC' | aBC' | aC' | abB'CB | abCB | aB | a C’ → AB'CBC' | ACBC' | CC' | AB'CB | ACB | C