Ciele
- Oboznámiť sa s transformáciami bezkontextových gramatík.
- Precvičiť si transformácie bezkontextových gramatík.
Úvod
Transformácia gramatiky predstavuje postup, pomocou ktorého získame z danej gramatiky ekvivalentnú gramatiku, čiže takú, ktorá generuje ten istý jazyk, ale zároveň spĺňa určité dodatočné požiadavky. Tieto transformácie sú v praxi veľmi dôležité, pretože umožňujú gramatiku zjednodušiť, odstrániť z nej problémové konštrukcie alebo ju prispôsobiť konkrétnej metóde syntaktickej analýzy, ako je napríklad rekurzívna syntaktická analýza zhora nadol.
V tejto kapitole sa oboznámime s rôznymi druhmi transformácií bezkontextových gramatík, ako sú napríklad odstránenie ľavej rekurzie, odstránenie ε-pravidiel či úprava gramatiky na požiadavky deterministických analyzátorov. Zároveň si tieto transformácie prakticky precvičíme a ukážeme si, ako ich využiť pri implementácii syntaktického analyzátora a interpretátora pre jazyk aritmetických výrazov, ktorý bude vychádzať práve z transformovanej gramatiky.
Postup
Krok 1
V praxi sa možeme stretnúť s gramatikami, ktoré obsahujú rôzne "nedokonalosti" alebo prvky, ktoré komplikujú ich spracovanie, na zákalde čoho nie je možné zostrojiť ich syntaktický analyzátor konkrétneho typu. Transformácie gramatík nám umožňujú tieto nedokonalosti odstrániť a previesť gramatiku do štandardizovanej ekvivalentnej formy, ktorá je vhodnejšia pre praktické použitie resp. dovoľuje zostrojenie syntaktického analyzátora konkrétneho typu.
Medzi základné transformácie bezkontextových gramatík patria:
- odstránenie nadbytočných symbolov gramatiky,
- odstránenie $\varepsilon$-pravidiel,
- odstránenie jednoduchých pravidiel a cyklov,
- odstránenie ľavej rekurzie a ľavá faktorizácia.
Redukovaná bezkontextová gramatika je bezkontextová gramatika bez nadbytočných symbolov.
Vlastná bezkontextová gramatika je bezkontextová gramatika bez cyklu, bez $\varepsilon$-pravidiel a bez nadbytočných symbolov.
Teraz sa na jednotlivé úpravy pozrieme bližšie.
Odstránenie nadbytočných symbolov gramatiky
Nedostupný symbol je taký symbol $\beta \in N \cup T$ (terminál alebo neterminál) gramatiky, ktorý sa neobjavuje v žiadnej vetnej forme. Neexistuje teda derivácia $ S \Rightarrow^* \alpha \beta \gamma $, kde $S$ je počiatočný neterminál a $ \alpha, \gamma \in (N \cup T)^* $.
Nadbytočný symbol je taký symbol $\beta \in N \cup T$ (terminál alebo neterminál) gramatiky, ktorý je nedostupný alebo ktorého výskyt v rámci vetnej formy spôsobí, že žiadnou deriváciou nie je možné túto vetnú formu transformovať na vetu. Neexistuje teda derivácia $ S \Rightarrow^* \alpha\beta\gamma \Rightarrow^* w $, kde $S$ je počiatočný neterminál $\alpha,\gamma\in(N\cup T)^*$ a $ w \in T^*$.
Poznámka
Každý nedostupný symbol je nadbytočný. Obrátené tvrdenie však neplatí: nie každý nadbytočný symbol je nedostupný.
Odstránenie nadbytočných symbolov z bezkontextovej gramatiky pozostáva z nasledujúcich krokov:
- Iteratívna konštrukcia množiny neterminálych symbolov $N_T$, ktoré môžu generovať terminálne reťazce (slová).
- Odstránenie všetkých neterminálnych symbolov z gramatiky, ktoré nepatria do množiny $N_T$.
- Iteratívna konštrukcia množiny dostupných symbolov $V_D$ (možno vykonať až po ukončení predchádzajúcich krokov).
- Odstránenie všetkých symbolov z gramatiky, ktoré nepatria do množiny $V_D$.
Množinu všetkých neterminálnych symbolov, ktoré môžu generovať terminálne reťazce, určime pomocou nasledujúceho Algoritmu 1.
Algoritmus 1. Konštrukcia množiny neterminálnálnych sybolov, ktoré môžu generovať terminálne reťazce.
Vstup: Bezkontextová gramatika $G=(N,T,P,S)$.
Výstup: Množina neterminálov $N_T$, ktoré môžu generovať terminálne reťazce.
- $N_T\leftarrow\emptyset$;
- opakuj
- $\acute{N}_T\leftarrow N_T$;
- $N_T\leftarrow\acute{N}_T \cup \{A\;|\;A\to\alpha\in P \;\land\;\alpha\in(\acute{N}_T\cup T)^{*}\}$;
- pokiaľ $N_T\neq\acute{N}_T$
Množinu všetkých dostupných symbolov gramatiky určíme pomocou nasledujúceho Algoritmu 2.
Algoritmus 2. Konštrukcia množiny dostupných symbolov gramatiky.
Vstup: Bezkontextová gramatika $G=(N,T,P,S)$.
Výstup: Množina dostupných symbolov $V_D$ gramatiky $G$.
- $V_D\leftarrow\{S\}$;
- opakuj
- $\acute{V}_D\leftarrow V_D$;
- $V_D\leftarrow\acute{V}_D \cup \{\beta\;|\;A\to\alpha\beta\gamma\in P \;\land\; \beta\in (N\cup T) \;\land\;A\in\acute{V}_D\;\land\;\alpha,\gamma\in(N\cup T)^{*}\};$
- pokiaľ $V_D\neq\acute{V}_D$
Príklad
Daná je bezkontextová gramtika $G = (\{$S
, A
, B
, C
, D
$\}, \{$a
, b
, c
$\}$, $P$, S
$)$, kde $P$ je množina pozostávajúca z nasledujúcich pravidiel:
${}$ |
---|
S $\to$ AB | C |
A $\to$ aA | a |
B $\to$ bB |
C $\to$ c |
D $\to$ bc . |
Transformujte gramatiku $G$ na gramatiku $G'$, ktorá neobsahuje nadbytočné symboly a pre ktorú platí: $L(G) = L(G')$.
Riešenie
Najprv musíme pristúpiť k identifikácii a následnej eliminácii neterminálov, ktoré nedokážu generovať slova jazyka (terminálne reťazce). Tie zistíme ako rozdiel množiny všetkých neterminálov $N$ a množiny $N_T$, ktorú získame ako výsledok aplikácie Algoritmu 1.
Po inicializácii $N_T$ prázdnou množinou sú hodnoty $N_T$ a $\acute{N}_T$ v jednotlivých iteráciách za ňou nasledujúceho logického cyklu v momente vyhonotenia jeho podmienky prehľadne prezentované v nasledujúcej tabuľke.
Iterácia logického cyklu | Množina $N_T$ | Množina $\acute{N}_T$ | Podmienka cyklu $N_T\neq\acute{N}_T$ |
---|---|---|---|
1. | $\{$A,C,D $\}$ |
$\emptyset$ | $\mathit{true}$ |
2. | $\{$A,C,D,S $\}$ |
$\{$A,C,D $\}$ |
$\mathit{true}$ |
3. | $\{$A,C,D,S $\}$ |
$\{$A,C,D,S $\}$ |
$\mathit{false}$ |
Keďže B
$\not\in N_T$, neterminálny symbol B
je nadbytočný a z gramatiky ho odstránime. Gramatika $G''$ (po prvej fáze transformácie) tak bude vyzerať nasledovne:
$G'' = (\{$S
, A
, C
, D
$\}$, $\{$a
, b
, c
$\}$, $P''$, S
$)$, kde $P''$ je množina pozostávajúca z nasledujúcich pravidiel:
${}$ |
---|
S $\to$ C $\quad$(odstránili sme S $\to$ AB , pretože obsahuje B ) |
A $\to$ aA | a |
C $\to$ c |
D $\to$ bc . |
Následne môžeme pristúpiť k identifikácii a eliminácii nedostupných sybolov gramatiky $G''.$ Tie ziskame ako rozdiel množiny všetkých symbolov $N\cup T$ a množiny $V_D$, ktorú získame ako výsledok aplikácie Algoritmu 2.
Po inicializácii $V_D$ množinou obsahujúcou počiatočný sybolom gramatiky S
sú hodnoty $V_D$ a $\acute{V}_D$ v jednotlivých iteráciách za ňou nasledujúceho logického cyklu v momente vyhodnotenia jeho podmienky prehľadne prezentované v nasledujúcej tabuľke.
Iterácia logického cyklu | Množina $V_D$ | Množina $\acute{V}_D$ | Podmienka cyklu $V_D\neq\acute{V}_D$ |
---|---|---|---|
1. | $\{$S,C $\}$ |
$\{$S $\}$ |
$\mathit{true}$ |
2. | $\{$S,C,c $\}$ |
$\{$S,C $\}$ |
$\mathit{true}$ |
3. | $\{$S,C,c $\}$ |
$\{$S,C,c $\}$ |
$\mathit{false}$ |
Keďže symboly A
, D
, a
, b
$\notin V_D$, sú nadbytočné a z gramatiky ich môžeme odstrániť. Výsledná gramatika $G'$ bez nadbytočných symbolov bude vyzerať nasledovne:
$G' = (\{$S
, C
$\}$, $\{$c
$\}$,$\{$S
$\to$ C
, C
$\to$ c
$\}$, S
$)$.
Odstránenie $\boldsymbol\varepsilon$-pravidiel
Pravidlo sa nazýva $\boldsymbol\varepsilon$-pravidlo, ak je tvaru $A \rightarrow \varepsilon$, kde $A$ je ľubovoľný neterminál. Intuitívne nám toto pravidlo hovorí, že daný neterminál môže v priebehu derivácie kedykoľvek zmiznúť.
Gramatika sa nazýva gramatika bez $\boldsymbol\varepsilon$-pravidiel, ak jej množina pravidiel $P$ neobsahuje žiadne $\varepsilon$-pravidlo alebo v $P$ existuje jediné $\varepsilon$-pravidlo $S\to \varepsilon$, pričom začiatočný symbol gramatiky $S$ sa nevyskytuje na pravej strane žiadneho pravidla.
Odstránenie $\varepsilon$-pravidiel z bezkontextovej gramatiky pozostáva z nasledujúcich krokov:
- Iteratívna konštruukcia množiny $N_\varepsilon$ obsahujúcej všetky neterminály, ktoré možno priamo či nepriamo prepísať na prázdny reťazec.
- Úprava pravidiel gramatiky na základe množiny $N_\varepsilon$.
Poznámka
$N_\varepsilon$ predstavuje množinu neterminalov, ktoré sa počas derivácie možu "stratiť".
Najprv predstavíme algoritmus konštrukcie množiny $N_\varepsilon$.
Algoritmus 3. Konštrukcia množiny neterminálov, ktoré môžu generovať $\varepsilon$.
Vstup: Bezkontextová gramatika $G=(N,T,P,S)$.
Výstup: Množina neterminálov $N_\varepsilon$, ktoré môžu generovať $\varepsilon$.
- $N_\varepsilon\leftarrow\emptyset$;
- opakuj
- $\acute{N}_\varepsilon\leftarrow N_\varepsilon$;
- $N_\varepsilon\leftarrow\acute{N}_\varepsilon \cup \{A\;|\;A\to\alpha\in P \;\land\;\alpha\in\acute{N}_\varepsilon^{*}\}$;
- pokiaľ $N_\varepsilon\neq\acute{N}_\varepsilon$
Postup úpravy prepisovacích pravidiel gramatiky na základe množiny $N_\varepsilon$ prezentuje nasledujúci Algoritmus 4.
Algoritmus 4. Úprava pravidiel gramatiky na základe množiny $N_\varepsilon$.
Vstup: Bezkontextová gramatika $G=(N,T,P,S)$ a množina neterminálov $N_\varepsilon$, ktoré môžu generovať $\varepsilon$.
Výstup: Bezkontextová gramatika $G'$ bez $\varepsilon$-pravidiel.
- $P'\leftarrow P$; kde $P'$ je nová množina prepisovacích pravidiel gramatiky $G'$
- pre všetky $A \to \varepsilon \in P'$ vykonaj
- ak $A\neq S$ potom
- $P' \leftarrow P' - \{A \to \varepsilon\}$;
- koniec ak
- ak $A=S$ a $S$ sa vyskytuje na pravej strane nejakého pravidla z $P'$ potom
- $P' \leftarrow P' - \{S \to \varepsilon\}$;
- $P' \leftarrow P' \cup \{S' \rightarrow S \mid \varepsilon\}$; kde $S'$ je nový počiatočný symbol gramatiky $G'$
- koniec ak
- koniec pre
- pre všetky $A \to \beta \in P'$ vykonaj
- ak $\beta = \alpha_0B_1\alpha_1B_2\ldots B_k\alpha_k,$ kde $\alpha_0,\ldots, \alpha_k \in ((N-N_\varepsilon)\cup T)^*$, $B_1,\ldots, B_k\in N_\varepsilon$ potom
- $P'\leftarrow P'\cup\{A \to \alpha_0X_1\alpha_1X_2\ldots X_k\alpha_k \mid X_i=B_i \;\lor\; X_i=\varepsilon,\text{ pre }i=1,2,\ldots,k\};$
- koniec ak
- ak $A\neq S$ potom
- $P' \leftarrow P' - \{A \to \varepsilon\}$;
- koniec ak
- koniec pre
Slovný opis Algoritmu 4.
- Z gramatiky najprv odstránime všetky $\varepsilon$-pravidlá, výnimkou je len pravidlo pre počiatočný symbol. Ak $S \in N_\varepsilon$, potom pravidlo $S \rightarrow \varepsilon$:
- v gramatike ponecháme, ak sa $S$ nevyskytuje na pravej strane židneho pravidla,
- inak toto pravidlo odstránime, ale do gramatiky pridáme nový počiatočný neterminál $S'$ s pravidlami $S' \rightarrow S \mid \varepsilon$.
- Postupne prejdeme jednotlivé pravidlá v gramatike. Ak sa na pravej strane vyskytuje nejaký neterminál z množiny $N_\varepsilon$, teda pravidlo bude tvaru: $$A \to \alpha_0B_1\alpha_1B_2\ldots B_k\alpha_k,$$ kde $\alpha_0,\ldots, \alpha_k \in ((N-N_\varepsilon)\cup T)^*$, $B_1,\ldots, B_k\in N_\varepsilon$, potom toto pravidlo nahradíme sadou pravidiel tvaru $$A \to \alpha_0X_1\alpha_1X_2\ldots X_k\alpha_k,$$ kde $X_i=B_i$ alebo $X_i=\varepsilon$, pre $i\in\{1,2,\ldots,k\}$. Ak by pritom vzniklo pravidlo tvaru $A \to \varepsilon$ a $A\neq S$, pravidlo do gramatiky nepridáme.
Poznámka
Druhý bod vyjadruje skutočnosť, že v prípade, ak sa na pravej strane pravidla vyskytuje viac než jeden neterminál z množiny $N_\varepsilon$, je nutné pridať pravidlá, ktorých pravé strany predstavujú všetky možné kombinácie bez týchto neterminálov.
Príklad
Nech je daná bezkontextová gramatika $G = (\{$S
, A
, B
$\}$, $\{$a
, b
$\}$, $P$, S
$)$, kde $P$ obsahuje nasledujúce pravidlá:
${}$ |
---|
S $\to$ AB |
A $\to$ aA | $\varepsilon$ |
B $\to$ bB | $\varepsilon$. |
Odstráňte z tejto gramatiky $\varepsilon$-pravidlá.
Riešenie
Najprv konštuujeme množinu $N_\varepsilon$ aplikáciou Algoritmu 3.
Po inicializácii $N_\varepsilon$ prázdnou množinou sú hodnoty $N_\varepsilon$ a $\acute{N}_\varepsilon$ v jednotlivých iteráciách za ňou nasledujúceho logického cyklu v momente vyhonotenia jeho podmienky prehľadne prezentované v nasledujúcej tabuľke.
Iterácia logického cyklu | Množina $N_\varepsilon$ | Množina $\acute{N}_\varepsilon$ | Podmienka cyklu $N_\varepsilon\neq\acute{N}_\varepsilon$ |
---|---|---|---|
1. | $\{$A ,B $\}$ |
$\emptyset$ | $\mathit{true}$ |
2. | $\{$A ,B ,S $\}$ |
$\{$A ,B $\}$ |
$\mathit{true}$ |
3. | $\{$A ,B ,S $\}$ |
$\{$A ,B ,S $\}$ |
$\mathit{false}$ |
Následne pristúpime k úprave pravidiel.
- Odstránime všetky $\varepsilon$-pravidlá, v tomto prípade:
A
$\to$ $\varepsilon$ aB
$\to$ $\varepsilon$. - Upravíme pravidlo
S
$\to$AB
na sadu pravidiel:S
$\to$AB | A | B |
$\varepsilon\quad$ (pretožeA
,B
$\in N_\varepsilon$). - Upravíme pravidlo
A
$\to$aA
na sadu pravidiel:A
$\to$aA | a
$\quad$(pretožeA
$\in N_\varepsilon$). - Upravíme pravidlo
B
$\to$bB
na sadu pravidiel:B
$\to$bB | b
$\quad$(pretožeB
$\in N_\varepsilon$).
Výsledná gramatika je $G' = (\{$S
, A
, B
$\}$, $\{$a
, b
$\}$, $P'$, S
$)$, kde $P'$ obsahuje nasledujúce pravidlá:
${}$ |
---|
S $\to$ AB | A | B | $\varepsilon$ |
A $\to$ aA | a |
B $\to$ bB | b . |
Odstránenie jednoduchých pravidiel a cyklov
Jednoduché pravidlo je pravidlo tvaru $A \to B$, kde $A$ a $B$ sú ľubovoľné neterminály. Intuitívne nám toto pravidlo hovorí, že neterminál $A$ na ľavej strane sa "vie správať rovnako", ako neterminál $B$ na pravej strane.
Bezkontextová gramatika bez cyklu je taká bezkontextová gramatika, kde nie je pre žiadny neterminál možná derivácia $A \Rightarrow^+ A$. Platí, že ak je gramatika bez jednoduchých a $\varepsilon$-pravidiel, potom je bez cyklu (obrátene platiť nemusí).
Odstránenie jednoduchých pravidiel z bezkontextovej gramatiky pozostáva z nasledujúcich krokov:
- Iteratívna konštruukcia množiny neterminálov $N_A$, ktoré je možné odvodiť z daného neterminálu $A$.
- Úprava pravidiel gramatiky na základe množiny $N_A$
Najprv predstavíme algoritmus konštrukcie množiny $N_A$.
Algoritmus 5. Konštrukcia množiny neterminálov, ktoré je možné odvodiť z daného neterminálu $A$.
Vstup: Bezkontextová gramatika $G=(N,T,P,S)$ a neterminál $A\in N$.
Výstup: Množina neterminálov $N_A$, ktoré je možné odvodiť z daného neterminálu $A$.
- $N_A\leftarrow\{A\}$;
- opakuj
- $\acute{N}_A\leftarrow N_A$;
- $N_A\leftarrow\acute{N}_A \cup \{C\;|\;B\to C\in P \;\land\;B\in\acute{N}_A\}$;
- pokiaľ $N_A\neq\acute{N}_A$
Teraz sa bližšie pozrieme na postup úpravu prepisovacích pravidiel gramatiky na základe množiny $N_A$ vyjadrený nasledujúcim Algoritmom 6.
Algoritmus 6. Úprava pravidiel gramatiky na základe množín $N_A$, pre každý neterminál $A\in N$.
Vstup: Bezkontextová gramatika $G=(N,T,P,S)$ a množina neterminálov $N_A$, ktoré je možné odvodiť z daného neterminálu $A$ pre každý neterminál $A\in N$.
Výstup: Bezkontextová gramatika $G'=(N,T,P',S)$ bez jednoduchých pravidiel.
- $P'\leftarrow P$
- odstráň všetky jednoduché pravidlá z $P'$
- pre všetky $N_A$, kde $A \in N$ vykonaj
- pre všetky $B\in N_A$ vykonaj
- pre všetky $B\to \alpha \in P$ vykonaj
- ak $B\to \alpha$ nie je jednoduché pravidlo potom
- $P'\leftarrow P'\cup\{A\to\alpha\}$
- koniec ak
- koniec pre
- koniec pre
- koniec pre
Príklad
Nech je daná gramtika $G = (\{$S
, A
, B
, C
, D
$\}$, $\{$a
, b
, c
, d
$\}$, $P$, S
$)$, kde $P$ obsahuje nasledujúce prepisovacie pravidlá:
${}$ |
---|
S $\to$ A | B |
A $\to$ C | aA | bS |
B $\to$ D | cB | dS |
C $\to$ bC | a |
D $\to$ dD | c . |
Transformujte gramatiku $G$ na bezkontextovú gramatiku $G'$, ktorá neobsahuje jednoduché pravidlá a pre ktorú platí: $L(G) = L(G')$.
Riešenie
Najprv potrebujeme konštruovať množiny $N_A$ pre každý neterminálny symbol $A\in N$.
Konštrukcia $N_S:$
Iterácia logického cyklu | Množina $N_S$ | Množina $\acute{N}_S$ | Podmienka cyklu $N_S\neq\acute{N}_S$ |
---|---|---|---|
1. | $\{$S ,A ,B $\}$ |
$\{$S $\}$ |
$\mathit{true}$ |
2. | $\{$S ,A ,B ,C ,D $\}$ |
$\{$S ,A ,B $\}$ |
$\mathit{true}$ |
3. | $\{$S ,A ,B ,C ,D $\}$ |
$\{$S ,A ,B ,C ,D $\}$ |
$\mathit{false}$ |
Konštrukcia $N_A:$
Iterácia logického cyklu | Množina $N_A$ | Množina $\acute{N}_A$ | Podmienka cyklu $N_A\neq\acute{N}_A$ |
---|---|---|---|
1. | $\{$A ,C $\}$ |
$\{$A $\}$ |
$\mathit{true}$ |
2. | $\{$A ,C $\}$ |
$\{$A ,C $\}$ |
$\mathit{false}$ |
Konštrukcia $N_B:$
Iterácia logického cyklu | Množina $N_B$ | Množina $\acute{N}_B$ | Podmienka cyklu $N_B\neq\acute{N}_B$ |
---|---|---|---|
1. | $\{$B ,D $\}$ |
$\{$B $\}$ |
$\mathit{true}$ |
2. | $\{$B ,D $\}$ |
$\{$B ,D $\}$ |
$\mathit{false}$ |
Konštrukcia $N_C:$
Iterácia logického cyklu | Množina $N_C$ | Množina $\acute{N}_C$ | Podmienka cyklu $N_C\neq\acute{N}_C$ |
---|---|---|---|
1. | $\{$C $\}$ |
$\{$C $\}$ |
$\mathit{false}$ |
Konštrukcia $N_D:$
Iterácia logického cyklu | Množina $N_D$ | Množina $\acute{N}_D$ | Podmienka cyklu $N_D\neq\acute{N}_D$ |
---|---|---|---|
1. | $\{$D $\}$ |
$\{$D $\}$ |
$\mathit{false}$ |
Z gramatiky odstránime všetky jednoduché pravidla, v tomto prípade:
S
$\to$A
,S
$\to$B
,A
$\to$C
aB
$\to$D
.
Následne použitím príslušnej množiny upravíme pravidlá pre jednotlivé neterminály.
-
Pravidlá pre
S
upravíme pomocou množiny $N_S=\{$S
,A
,B
,C
,D
$\}$:S
$\to$aA | bS | cB | dS | bC | a | dD | c
. -
Pravidlá pre
A
upravíme pomocou množiny $N_A=\{$A
,C
$\}$:A
$\to$aA | bS | bC | a
. -
Pravidlá pre
B
upravíme pomocou množiny $N_B=\{$B
,D
$\}$:B
$\to$cB | dS | dD | c
. -
Pravidlá pre
C
upravíme pomocou množiny $N_C=\{$C
$\}$:C
$\to$bC | a
. -
Pravidlá pre
D
upravíme pomocou množiny $N_D=\{$D
$\}$:D
$\to$dD | c
.
Výsledná gramatika bez jednoduchých pravidiel vyzerá nasledovne $G' = (\{$S
, A
, B
, C
, D
$\}$, $\{$a
, b
, c
, d
$\}$, $P'$, S
$)$, kde $P$ je množina nasledujúcich prepisovacích pravidiel:
${}$ |
---|
S $\to$ aA | bS | cB | dS | bC | a | dD | c |
A $\to$ aA | bS | bC | a |
B $\to$ cB | dS | dD | c |
C $\to$ bC | a |
D $\to$ dD | c . |
Odstránenie ľavej rekurzie a ľavá faktorizácia
Posledné dve transformačné metódy zohrávajú kľúčovú úlohu pri tzv. determinizácii bezkontextových gramatík a tvorbe deterministických syntaktických analyzátorov, ktorým sa budeme bližšie venovať v nasledujúcom cvičení 8.
Jednou z najčastejších prekážok pri použití gramatiky v deterministickej analýze zhora nadol je výskyt ľavej rekurzie. Tento jav bráni konštrukcii efektívnych syntaktických analyzátorov, a preto je potrebné ho pred samotnou analýzou odstrániť.
Neterminálny symbol $A$ je rekurzívny zľava, ak existuje derivácia $A \Rightarrow^+ A\beta$, kde $\beta \in (N \cup T)^*$. Rozlišujeme dva typy ľavej rekurzie:
- Priama ľavá rekurzia, ak $A \Rightarrow^1 A\beta$. V množine pravidiel preto musí existovať prepisovacie pravidlo tvaru $A \to A\beta$ (tento typ ľavej rekurzie je viditeľný priamo v pravidlách pre daný neterminál, napríklad $A \to Aa$).
- Nepriama ľavá rekurzia, ak $A \Rightarrow^k A\beta$, kde $k>1$. Tento typ ľavej rekurzie nie je viditeľný priamo v pravidlách pre daný neterminál, napríklad $A \to Ba$, $B \to Ac$.
Ľavo rekurzívna gramatika je taká gramatika, ktorá má aspoň jeden ľavo rekurzívny neterminálny symbol.
Pravidlá, ktoré sú zdrojom priamej ľavej rekurzie, je možné z gramatiky odstrániť nasledujúcou transformáciou: Pravidlo
$$A \rightarrow A\alpha \mid \beta \quad $$ možno zameniť za sadu pravidiel: $$ \begin{align*} A &\rightarrow \beta A' \mid \beta\\ A' &\rightarrow \alpha A' \mid \alpha, \end{align*} $$ kde $\alpha, \beta \in (N \cup T)^*, A \in N$.
Pre viac alternatív $\alpha, \beta $ možno schému intuitívne rozšíriť nasledovne. Predidlo $$A \rightarrow A\alpha_1 \mid \ldots \mid A\alpha_n \mid \beta_1 \mid \ldots \mid \beta_m $$ možno zameniť za sadu pravidiel: $$ \begin{align*} A &\rightarrow \beta_1 A' \mid \ldots \mid \beta_m A' \mid \beta_1 \mid \ldots \mid \beta_m\\ A' &\rightarrow \alpha_1 A' \mid \ldots \mid \alpha_n A' \mid \alpha_1 \mid \ldots \mid \alpha_n, \end{align*} $$ kde $\alpha_i, \beta_i \in (N \cup T)^*, A \in N$.
Príklad
Ostráňte priamu ľavú rekurziu z bezkontextovej gramatiky $G=(\{$X
,Y
$\}$,$\{$a
,b
,c
$\}$,$P$,A
$)$, kde $P$ je množina nasledujúcich pravidiel:
${}$ |
---|
X $\to$ Xab | cY |
Y $\to$ b . |
Riešenie
Najprv v pravidlách gramatiky $G$ identifikujeme vzory z vyššie uvedenej schémy:
- $A =$
X
, - $\alpha =$
ab
, - $\beta =$
cY
.
Následne možno pristúpiť k odstráneniu ľavej rekurzie zavedením nového pravo rekurzívneho neterminálu X
', a to nasledovne:
${}$ |
---|
X $\to$ cYX '$\;\;$| cY |
X ' $\to$ abX '$\;\;$| ab . |
Príklad
Transformujte gramatiku $G=(\{$E
, T
, F
$\}$, $\{$+
, *
, (
, )
$\}$, $P$, E
$)$, kde $P$ je množina nasledujúcich pravidiel:
${}$ |
---|
E $\to$ E + T | T |
T $\to$ T * F | F |
F $\to$ cislo | ( E ) |
Riešenie
Gramatika obsahuje dva ľavo rekurzívne neterminály E
a T
. K odstráneniu ľavej rekurzie z prepisovacích pravidiel gramatiky preto pristúpime nahradením pravidiel
${}$ | ${}$ | ${}$ |
---|---|---|
E $\to$ E + T | T , |
$\phantom{halohalohalo}$ | T $\to$ T * F | F |
dvojicami pravidiel:
${}$ | ${}$ | ${}$ |
---|---|---|
E $\to$ T E '$\;\;$| T |
$\phantom{halohalohalo}$ | T $\to$ F T '$\;\;$| F , |
E ' $\to$ + T E '$\;\;$| + T |
${}$ | T ' $\to$ * F T '$\;\;$| * F , |
na základe čoho získame gramatiku $G'=(\{$E
,E
',T
,T
',F
$\}$,$\{$+
,*
,(
,)
$\}$,$P'$,E
$)$, kde $P'$ je množina nasledujúcich pravidiel:
${}$ |
---|
E $\to$ T E '$\;\;$| T |
E ' $\to$ + T E '$\;\;$| + T |
T $\to$ F T '$\;\;$| F |
T ' $\to$ * F T '$\;\;$| * F |
F $\to$ cislo | ( E ) . |
Vyčlenenie spoločných symbolov zľava tzv. ľavá faktorizácia, ktorá predstavuje nasledujúci princíp transformácie gramatiky. Pravidlá
${}$ $A \to \alpha X\beta_1$ $A \to \alpha Y \beta_2$
nahradíme sadou pravidiel:
${}$ $A \to \alpha B$ $B \to X \beta_1$ $B \to Y \beta_2$.
Príklad
Transformujte výslednú gramatiku z predchádzajúceho príkladu prostrednítvom ľavej faktorizácie.
Riešenie
Ľavou faktorizáciou výslednej gramatiky z predchádzajúceho príkladu získame gramatiku $G''=(\{$E
,E
',E
'',T
,T
',T
'',F
$\}$,$\{$+
,*
,(
,)
$\}$,$P''$,E
$)$, kde možina pravidiel $P''$ pozostáva z nasledujúcich pravidiel:
${}$ |
---|
E $\to$ T E '' |
E '' $\to$ E '$\;\;$| $\;\;\varepsilon$ |
E ' $\to$ + T E '' |
T $\to$ F T '' |
T '' $\to$ T '$\;\;$| $\;\;\varepsilon$ |
T ' $\to$ * F T '' |
F $\to$ cislo | ( E ) . |
Túto gramatiku možno ešte zjednodušiť. Keďže pre neterminál E
' existuje len jediné prepisovacie pravidlo, všetky výskyty tohto neterminálu na pravej strane pravidiel možno nahradiť pravou stranou tohto pravidla teda vetnou formou + T E
'' (obdobne postupujeme pri netreminálnom symbole T
'). Výsledkom je gramatika $G^F=(\{$E
,E
'',T
,T
'',F
$\}$,$\{$+
,*
,(
,)
$\}$,$P^F$,E
$)$, kde $P^F$ je množina nasledujúcich pravidiel:
${}$ |
---|
E $\to$ T E '' |
E '' $\to$ + T E ''$\;\;$| $\;\;\varepsilon$ |
T $\to$ F T '' |
T '' $\to$ * F T ''$\;\;$| $\;\;\varepsilon$ |
F $\to$ cislo | ( E ) . |
Krok 2
Úloha 2.1
Transformujte bezkontextovú gramatiku $G$ na gramatiku $G'$, ktorá nebude obsahovať nadbytočné symboly a $L(G) = L(G')$.
Gramatika $G$ je daná nasledovne: $G = (\{$S
, A
, B
, C
, D
$\}$, $\{$0
,1
$\}$, $P$, S
$)$, kde $P$ je množina prepisovacích pravidiel:
${}$ |
---|
S $\to$ 0S | 1D | $\varepsilon$ |
A $\to$ 0CB | 0AD |
B $\to$ 1B | 110 |
C $\to$ 1CC | 0A1B |
D $\to$ 11A | 0D00 | 1S | $\varepsilon$. |
Zobraziť riešenie
Odpoveď:
Úloha 2.2
Transformujte bezkontextovú gramatiku $G$ na gramatiku $G'$, ktorá nebude obsahovať $\varepsilon$-pravidlá a $L(G) = L(G')$. Gramatika $G$ je daná nasledovne: $G = (\{$S
, A
, B
, C
, D
$\}$, $\{$0
,1
,2
,3
$\}$, $P$, S
$)$, kde $P$ je množina prepisovacích pravidiel:
${}$ |
---|
S $\to$ 0A0 | 0 |
A $\to$ BC | 2 | CCC |
B $\to$ 1C | 3D | $\varepsilon$ |
C $\to$ A3 | $\varepsilon$ |
D $\to$ A | 2 . |
Zobraziť riešenie
Odpoveď:
Úloha 2.3
Transformujte bezkontextovú gramatiku $G$ na gramatiku $G'$, ktorá nebude obsahovať jednoduché pravidlá a $L(G) = L(G')$.
Gramatika $G$ je daná nasledovne: $G = (\{$S
, A
, B
, C
$\}$, $\{$a
, b
$\}$, $P$, S
$)$, kde $P$ je množina prepisovacích pravidiel:
${}$ |
---|
S $\to$ aBa | A |
A $\to$ aA | B |
B $\to$ bB | AB | C | $\varepsilon$ |
C $\to$ bA | b . |
Zobraziť riešenie
Odpoveď:
Krok 3
V predchádzajúcom cvičení sme podrobne opísali proces návrhu gramatiky jazyka pre implementáciu jeho syntaktického analyzátora a interpretera metódou rekurzívneho zostupu. Uviedli sme, že asociativitu operátorov možno vyjadriť už na syntaktickej úrovni špecifikácie jazyka t. j. v gramatike prostredníctvom rekurzie (ľavú asosiativitu ľavou rekurziou a pravú asociativitu pravou rekurziou). V skutočnosti sme však pre vyjadrenie ľavej asociativity operátorov v gramatike v EBNF a v jej následnej implementácii nepoužili ľavú rekurziu ale iteráciu (opakovanie):
${}$ |
---|
E ::= T { "op" T } |
def E():
T()
# iterácia
while current_symbol in FIRST(op):
if current_symbol == op:
get_next_symbol()
else: error()
T()
na rozdiel od pravej asosiativity, ktorú sme vyjadrili a implementovali skutočnou pravou rekurziou:
${}$ |
---|
E ::= T [ "op" E ] |
def E():
T()
if current_symbol in FIRST(op):
if current_symbol == op:
get_next_symbol()
else: error()
E() # rekurzívne volanie
Pozrime sa preto na dôvod, ktorý viedol k tejto zmenne. Ak vychádzame z vyjadrenia ľavej asociativity operátorov v rámci gramatiky v BNF:
${}$ |
---|
<E> ::= <E> op <T> | <T> |
a transformujeme ju do EBNF tak, aby bola zachovaná ľavá rekurzia, získame gramatiku:
${}$ |
---|
E ::= [ E "op" ] T . |
Problém však nastáva pri jej implementácii, keďže procedúra zodpovedajúca netreminálnemu symbolu E
bude ako prvú procedúru v jej tele volať seba samú bez prvotného spracovania (redukcie) vstupu, čo vedie k problému nekonečnej rekurzie.
Úloha 3.1
Pozmente gramatiku aj implementáciu rekurzívneho syntaktického analyzátora jazyka aritmetických výrazov z predchádzajúceho cvičenia tak, aby ľavo asociatívne operátory skutočne využívali ľavú rekurziu a presvedče sa o zlyhaní tohto prístupu.
Úloha 3.2
Je možné problém ľavo rekurzívnej implementácie ľubovoľnej ľavo asociatívnej operácie na báze gramatiky v BNF vyriešiť doplňujúcou špecifikáciou precedencie pravidiel? Svoje tvrdenie detailne zdôvodnite.
Ľavú rekurziu však môžeme z gramatiky odstrániť tak, že ju nahradíme pravou rekurziou, čím zároveň eliminujeme potrebu využitia iteratívnych konštrukcií jazyka pri implementácii jeho syntaktického analyzátora metódou rekurzívneho zostupu. Takto navrhnutý analyzátor sa následne stáva plne rekurzívnym — celý proces spracovania vstupu je realizovaný výlučne pomocou volaní rekurzívnych funkcií, bez použitia cyklov.
Teraz pristúpime k návrhu plne rekurzívneho syntaktického analyzátora jazyka aritmetických výrazov. Vychádzať budeme z vyššie uvedenej tranformácie gramatiky tohto jazyka odstránením ľavej rekurzie. Výsledok tejto transtormácie prevedieme do EBNF, čím získame gramatiku $G=(\{$E
,E
',T
,T
',F
$\}$,$\{$+
,*
,(
,)
$\}$,$P'$,E
$)$, kde $P'$ je množina nasledujúcich pravidiel:
${}$ | ${}$ |
---|---|
E |
::= T [ E ' ] |
E ' |
::= + T [ E ' ] |
T |
::= F [ T ' ] |
T ' |
::= * F [ T ' ] |
F |
::= cislo | ( E ) . |
Úloha 3.3
Implementujte syntaktický analyzátor jazyka aritmetických výrazov metódou rekurzívneho zostupu na báze vyššie vyššie uvedenej gramatiky.
Nevýhodou tohto prístupu je však skutočnosť, že často vedie k strate prirodzenej väzby medzi syntaktickou štruktúrou a sémantickým významom výrazov, čo prezentuje aj nasledujúce porovnanie odvodzovacích stromov toho istého aritmetického výrazu.
1+2*3
pôvodnej gramatiky
1+2*3
transformovanej gramatiky
Samotný proces syntaxou riadenej interpretácia výrazov si následne vyžaduje modifikáciu, ktorej cieľom je zabezpečiť korektné priradenie významu jednotlivým výrazom. Nasledujúci obrázok ilustruje túto zmenu procesu itrerpretácie na konkrétnom príklade.
1+2*3
transformovanej gramatiky
Úloha 3.4
Transformujte syntaktický analyzátor z predchádzajúcej úlohy na interpretér. Inšpirujte sa schémou interpretácie konkrétneho aritmetického výrazu zachytenej na Obrázku 3.
Dotazník na ohodnotenie učiva
Vážení študenti,
týmto by sme Vás chceli požiadať o poskytnutie spätnej väzby k formátu a obsahu materiálov na cvičenia vo forme vyplnenie nasledujúceho dotazníka .
Tento dotazník slúži na ohodnotenie vašich skúseností s pripravenými materiálmi zo siedmeho cvičenia. Na vylepšovaní materiálov na základe vašej spätnej väzby aktívne pracujeme, a to s cieľom zvýšiť kvalitu, zrozumiteľnosť a prínosnosť výučby.