3.4. Przekształcenia gramatyk bezkontekstowych Definicje Niech będzie dana gramatyka bezkontekstowa G = <N, T, P, Z> G BK Symbol X (N T) nazywamy nieużytecznym w G G BK 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 G BK, jeśli X nie pojawia się w żadnej formie zdaniowej tej gramatyki (czyli nie można go wyprowadzić z Z). Gramatyka G G BK jest gramatyką bez ε-produkcji, gdy: (i) P nie zawiera produkcji postaci ε, N, 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> G BK można przekształcić do postaci równoważnej G = <N, T, P, Z> G BK (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. lgorytm usuwania symboli nieosiągalnych wejście: wyjście: G = <N, T, P, Z> G BK G = <N, T, P, Z> G BK taka, że (i) L(G ) = L(G) (ii) ( X (N T ) ) ( α,β (N T ) * ) ( Z * G αxβ ) V 0 := {Z}; i := 0; repeat i := i + 1; V i := V i-1 {X (N T) ( αxβ) P V i-1 α,β (N T) * }; until V i = V i-1 ; /* V i zawiera te symbole terminalne i nieterminalne które: - występują w produkcjach z P - dają się wyprowadzić z Z */ N := V i N;
T := V i T; P := {(u v) P u,v V * i } /* zawiera te produkcje z P, które zbudowane są z symboli z V i */ G := <N, T, P, Z> lgorytm usuwania symboli nieużytecznych wejście: G = <N, T, P, Z> G BK wyjście: G = <N, T, P, Z> G BK taka, że: (i) L(G ) = L(G) (ii) (N T ) nie zawiera symboli nieużytecznych N 0 := φ; /* φ - zbiór pusty */ i := 0; repeat i := i + 1; N i := N i-1 { N ( α) P α (N i-1 T) * } until N i = N i-1 ; G 1 := < N N i, T, P 1, Z> gdzie P 1 := {(u v) P u,v (N i T) * }; zastosować do G 1 algorytm usuwania symboli nieosiągalnych uzyskując w wyniku tego gramatykę G = <N, T, P, Z> G = <{S,, B}, {a, b}, {S a ; S ; B ; B b}, S> G 1 = <{S, B}, {a, b}, {S a ; B b}, S> G = <{S}, {a}, {S a}, S> lgorytm usuwania ε-produkcji wejście: G = <N, T, P, Z> G BK wyjście: G = <N, T, P, Z > G BK taka, że: (i) L(G) = L(G ) (ii) G jest gramatyką bez ε-produkcji N 0 := φ; /* φ - zbiór pusty */
i := 0; repeat i:= i + 1; * N i := N i-1 { N ( x) P x N i-1 }; until N i = N i-1 ; N e := N i ; /* N e = { N + G ε} */ P := P ; for ( x) P do przedstawiamy x w postaci α 0 B 1 α 1 B 2 α 2... B k α k, k 0, gdzie B i N e (1 i k), α i ((N T) N e ) * (0 i k); P := P {( α 0 X 1 α 1 X 2 α 2... X k α k ) : (X i = B i X i = ε)}; if ( ε) P then P := P {( ε)}; end; if Z N e then N := N {Z }; P := P {(Z Z), (Z ε)}; Z := Z ; end else N := N; Z := Z; end; 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: B ;, B N Gramatyka G zawiera cykle, wówczas gdy istnieją w gramatyce wyprowadzenia postaci + G ; N Cykle typu + powstają poprzez istnienie w gramatyce produkcji łańcuchowych, np. B, B C, C, 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> G BK można przekształcić do postaci równoważnej G = <N, T, P, Z> G BK (to znaczy takiej, że L(G ) = L(G) ) nie zawierającej produkcji łańcuchowych i cykli (w sensie powyższych definicji). lgorytm usuwania produkcji łańcuchowych i cykli wejście: wyjście: G = <N, T, P, Z> G BK ; G bez ε-produkcji! G = <N, T, P, Z> G BK taka, że (i) L(G) = L(G ) (ii) G nie zawiera produkcji łańcuchowych i cykli for N do N 0 := {}; i := 0; repeat i := i + 1; N i := N i-1 { C N (B C) P B N i-1 } until N i-1 = N i ; N := N i ; /* N = { B + G B } */ end; P := φ; /* φ - zbiór pusty */ for p P do if p = (B α) and α N then /* p nie jest łańcuchowa */ M B := { N B N };
for M B do /* M B = { : * G B} */ P := P { α }; end; end; 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: N E = { E, T, F } N T = { T, F } N F = { F } M E = { E } M T = { E, T } M F = { E, T, F } nalizujemy kolejno wszystkie produkcje gramatyki przekształcanej (1) E E + T (2) wypada, bo jest łańcuchowa (3) E T * F T T * F (4) wypada, bo jest łańcuchowa (5) E ( E ) T ( E ) F ( E ) (6) E id T id F id Definicja Gramatyka G = < N, T, P, Z > G BK 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 > G BK oraz symbol nieterminalny N.
Zbiór { α 1... α m β 1... β n } P jest zbiorem wszystkich produkcji mających po lewej stronie symbol ; żadne z β i (N T) * (i = 1,..., n) nie zaczyna się od symbolu. Niech G = < N { }, T, P, Z > będzie nową gramatyką, w której nowy symbol nieterminalny zaś zbiór produkcji P' jest określony jak niżej P = P { α 1... α m β 1... β n } { β 1... β n } { α 1... α m ε } Wówczas zachodzi L(G) = L(G ). Twierdzenie podaje sposób usuwania lewej rekursji, ale tylko bezpośredniej. α β α nalizowane α słowo : βααα α β Po modyfikacji: β ε β α α nalizowane α słowo : βααα α ε Twierdzenie 3.4.4. Każdą gramatykę bezkontekstową G = <N, T, P, Z> G BK można przekształcić do postaci równoważnej G = <N, T, P, Z> G BK (to znaczy takiej, że L(G ) = L(G) ) nie zawierającej (bezpośredniej i pośredniej) lewostronnej rekursji.
lgorytm usuwania (także pośredniej) rekursji lewostronnej wejście: wyjście: G = <N, T, P, Z> G BK, G gramatyka prawidłowa! G = <N, T, P, Z> G BK taka, że (i) G nie jest gramatyką lewostronnie rekursywną (ii) L(G ) = L(G) numerujemy symbole nieterminalne N := { 1,..., n }; n := #N N := N ; P := P ; i := 1 ; repeat if ( i i δ) P and δ (N T) * then N := N { i } P := P { i i α 1... i α q β 1... β p } { i β 1 i... β p i } { i α 1 i... α q i ε} end; /* q liczba wszystkich produkcji i i... (lewostr. rekurs.) żadne z β 1,..., β p nie zaczyna się od i p liczba wszystkich produkcji i... bez lewej rekursji */ if i = n then STOP else i := i + 1 ; for j := 1 to i 1 do P := P { i j α 1... j α x } { ( i γ k α l ) l = 1,..., x k = 1,..., m γ k prawe strony produkcji: j γ 1... γ k... γ m }; /* x liczba wszystkich produkcji typu i j α m liczba wszystkich produkcji typu j γ 1... γ m */ until FLSE ; /* w ten sposób prawa strona każdej produkcji i... zaczyna się albo od symbolu terminalnego, albo od nieterminala j o numerze j > i */
BC a B C b C B CC a Rodzaje rekursji lewostronnej: 1 2 3 B C B C rekursja posrednia rekursja bezposrednia I i = 1 G bez zmian II i = 2 ; j = 1 B C BCb ab I i = 2 B CB abb B CbB ε II i = 3 ; j = 1 C BCB ab CC a i = 3 ; j = 2 C CB CB abb CB ab CC a I i = 3 C abb CBC abc ac C B CBC CC ε Ostatecznie: BC a B CB abb B CbB ε C abb CBC abc ac C B CBC CC ε
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 > G BK oraz symbol nieterminalny N. Zbiór { α 1... α m β 1... β n } P jest zbiorem wszystkich produkcji mających po lewej stronie symbol ; żadne z β i (N T) * (i = 1,..., n) nie zaczyna się od symbolu. Niech G = < N { }, T, P, Z > będzie nową gramatyką, w której nowy symbol nieterminalny zaś zbiór produkcji P' jest określony jak niżej P = P { α 1... α m } { β 1... β n } { α 1... α m α 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). α β α nalizowane α słowo : βααα α β Po modyfikacji: β β β α α ' α α nalizowane α słowo : βααα
Drugi wariant algorytmu usuwania (także pośredniej) rekursji lewostronnej wejście: wyjście: G = <N, T, P, Z> G BK, G gramatyka prawidłowa G = <N, T, P, Z> G BK taka, że (i) G nie jest gramatyką lewostronnie rekursywną (ii) L(G ) = L(G) numerujemy symbole nieterminalne N := { 1,..., n }; n := #N N := N ; P := P ; i := 1 ; repeat if ( i i δ) P and δ (N T) * then N := N { i } P = P { i i α 1... i α q } { i β 1 i... β p i } { i α 1 i... α q i α 1... α q } end; /* q liczba wszystkich produkcji i i α r... (lewostr. rekurs.) żadne z β 1,..., β p nie zaczyna się od i p liczba wszystkich produkcji i β r... (bez lewej rekursji) */ if i = n then STOP else i := i + 1 ; for j := 1 to i 1 do P := P { i j α 1... j α x } { ( i γ k α l ) l = 1,..., x k = 1,..., m γ k prawe strony produkcji: j γ 1... γ k... γ m }; /* x liczba wszystkich produkcji typu i j α m liczba wszystkich produkcji typu j γ 1... γ m */ until FLSE ; /* w ten sposób prawa strona każdej produkcji i... zaczyna się albo od symbolu terminalnego, albo od nieterminala j o numerze j > i */
BC a B C b C B CC a I i = 1 G bez zmian II i = 2 ; j = 1 B C BCb ab I i = 2 B CB abb C ab B CbB Cb II i = 3 ; j = 1 C BCB ab CC a i = 3 ; j = 2 C CB CB abb CB CCB abcb ab CC a I i = 3 C abb'cbc' abcbc' abc' ac' abb'cb abcb ab a C B'CBC' CBC' CC' B'CB CB C Ostatecznie: BC a B CB abb C ab B CbB Cb C abb'cbc' abcbc' abc' ac' abb'cb abcb ab a C B'CBC' CBC' CC' B'CB CB C