Obsah

Transformace a normální formy bezkontextových gramatik

Derivace a derivační stromy

Gramatika (N, Σ, P, S)

Transformace

Úkol z TINu 2010, Úkol z TINu 2011

Odstranění nedostupných symbolů

Převod gramatiky (N, Σ, P, S) na gramatiku bez nedostupných stavů (N′, Σ′, P′, S)

  1. Najdeme všechny dostupné terminály a nonterminály
    1. i = 0
    2. V₀ = {S} (tj. v nultém kroku je dostupný pouze počáteční stav)
    3. repeat
      1. Vᵢ₊₁ = Vᵢ ∪ {X | AαXβPAVᵢ} (tj. do množiny dostupných přidáme všechny terminály a nonterminály, kterlé lze získat přepisem z některého nonterminálu z množiny dostupných z předchozího kroku)
      2. i++ (tj. přejdeme k dalšímu kroku)
    4. until Vᵢ₊₁ = Vᵢ₋₁ (tj. končíme pokud se nám v posledním kroku množina dostupných nezměnila)
  2. Novou gramatiku sestavíme jako:
    • N′ = VᵢN (tj. použijeme pouze dosažitelené nonterminály)
    • Σ′ = VᵢΣ (tj. použijeme pouze dosažitelené terminály)
    • P′ ⊂ P obsahuje pouze pravidla používající pouze symboly z Vᵢ

Odstranění zbytečných symbolů

Převod gramatiky (N, Σ, P, S) na gramatiku bez nedostupných stavů (N′, Σ, P′, S)

  1. Nalezení nonterminálů, které produkují terminální řetězce
    1. i = 0
    2. N₀ = ∅ (tj. v nultém kroku začínáme s prázdnou množinou nonterminálů generujících terminální řetězce)
    3. repeat
      1. Nᵢ₊₁ = Nᵢ ∪ {A | AαP ∧ α ∈ (NᵢΣ)*} (tj. do množiny všechny terminály, které lze přepsat na řetězce skladádající se pouze z terminálů nebo nonterminálů, které jsou již v množině nonterminálů generujících terminální řetězce)
      2. i++ (tj. přejdeme k dalšímu kroku)
    4. until Nᵢ₊₁ = Nᵢ₋₁ (tj. končíme pokud se nám v posledním kroku množina nezměnila)
  2. Vytvoříme gramatiku bez nonterminálů, které neprodukují terminální řetězce:
    • N′ = Nᵢ
    • P′ ⊂ P obsahuje pouze pravidla používající pouze symboly z Nᵢ
  3. Odstraníme nedostupné symboly z gramatiky

Odstranění ε-pravidel

Převod gramatiky (N, Σ, P, S) na gramatiku bez ε-pravidel (N′, Σ′, P′, S′)

  1. Sestavení množiny nonterminálů, které mohou generovat ε Nε
    • Postup je obdobný jako krok 1 algoritmu odstranění zbytečných symbolů pouze Nᵢ₊₁ = Nᵢ ∪ {A | AαPα ∈ (Nᵢ ∪ {ε})*}, Nε = Nᵢ
  2. Sestavíme novou množinu přepisovacích pravidel P
    • Jestliže AαBα₁…BₖαₖP, k ≥ 0 a všechna Bᵢ jsou v Nε a žádný symbol αᵢ není v Nε pak k P′ přidej všechny prvidla tvaru AαXαX₂…Xₖαₖ kde Xᵢ je buď Bᵢ nebo ε. Nepřidává se pravidlo A → ε.
    • Tj. od každého pravidla sestavíme všechny možné kombinace, kde jsou jednotlivé částí přepsatelné na ε vynechány
  3. Zavedeme nový počáteční nonterminál S
  4. Jestliže je S v Nε pak přidáme do P′ pravidla S′ → ε a S′ → S

Odstranění jednoduchých pravidel

Převod gramatiky bez ε-pravidel (N, Σ, P, S) na gramatiku bez jednoduchých pravidel (N, Σ, P′, S)

  1. Pro každé AN sestrojíme množinu NA = {B | A* B}
    1. i = 0
    2. N₀ = {A}
    3. repeat
      1. Nᵢ₊₁ = Nᵢ ∪ {C | BCPBNᵢ}
      2. i++
    4. until Nᵢ = Nᵢ₋₁ (tj. končíme pokud se nám v posledním kroku množina nezměnila)
    5. NA = Nᵢ
  2. Sestavíme novou množinu P
    • Pro všechna nejednoduchá pravidla Bα přidáme do P′ pravidla Aα pro všechna A pro něž platí BNA, tj. pro každého nejednoduché pravidlo najdeme všechny nonterminály A, které jdou jednoduchými pravidly přepsat na B, a vytvoříme všechny varianty pravidla, kde levou stranu nahradíme za A.

Odstranění levé rekurze

Převod vlastní gramatiky (N, Σ, P, S) na gramatiku bez levé rekurze (N′, Σ, P′, S).

Nonterminály vyjádříme jako N = {A₁, A₂, …, Aₙ} tj. zvolíme pořadí jednotlivých nonterminálů.

Gramatiku budeme transformovat tak, že je-li Aᵢα pravidlo pak α začíná buď terminálem nebo nonterminálem Aj, který je v pořadí až za Aᵢ (j > i).

  1. i = 1 (tj. začneme prvním nonterminálem v pořadí)
  2. Vezmeme všechna Aᵢ-pravidla, která jsou buď ve tvaru AᵢAᵢαₓ nebo Aᵢβₓ, kde β nezačíná nonterminálem, který je v pořadí před Aᵢ
    1. Přidáme nový nonterminál Aᵢ′ do N
    2. Všechna Aᵢ-pravidla nahradíme za:
      • Aᵢβ₁ | β₂ | … | βₓ (tj. přepisy na β zachováme)
      • AᵢβAᵢ′ | βAᵢ′ | … | βₓAᵢ′ (tj. pro všechny přepisy na β vytvoříme pravidla s vpravo přidaným Aᵢ′)
      • Aᵢ′ → α₁ | α₂ | … | αₓ (tj. u přepisů na Aᵢα vytvoříme pravidla pouze s α)
      • Aᵢ′ → αAᵢ′ | αAᵢ′ | … | αₓAᵢ′ (tj. u přepisů na Aᵢα vytvoříme pravidla s odstraněným Aᵢ a vpravo přidaným Aᵢ
      • Tím dosáhneme toho, že všechna Aᵢ-pravidla začínají buď terminálem nebo nonterminálem, který je v pořadí až za Aᵢ)
  3. Pokud jsme již prošli všechny nontermínály (i = n) končíme
  4. i++
  5. Pro všechny dosud procházené nonterminály Aj (1 < j < i)
    1. Pravidlo AᵢAjα odstraníme
    2. Pro každé Aj-pravidlo (Ajβ) vytvoříme Aᵢβα, tj. vezmeme všechna Aᵢ-pravidla, jejichž pravá strana začíná nonterminálem Aj, který je v pořadí před Aᵢ, a nahradíme je za pravidla ve kterých je Aj nahrazeno všemi řetězci na které jej lze přepsat.
  6. Jdeme na krok 2

Normální formy

Chomského normální forma (CNF)

Chomsky normal form

Přepisovací pravidla jsou pouze ve tvaru:

Převod vlastní gramatiky bez jednoduchých pravidel (N, Σ, P, S) na gramatiku v CNF (N′, Σ, P′, S′)

  1. Množina P′ obsahuje všechny pravidla z P ve tvaru ABC a Aa, případně Sε.
  2. Každé pravidlo tvaru AXX₂…Xₖ (k > 2) přepíšeme do P′ jako sérii pravidel:
    1. AXX₂′
    2. X₂′ → XX₃′
    3. Xₖ₋₁′ → Xₖ₋₁Xₖ
  3. Zavedeme nové non-terminální symboly AX₂′…Xₖ₋₁′ (tj. pravidla mající pravou stranu delší než dva prvky rozdělíme na navazující sérii pravidel majících napravo jen dva prvky)
  4. Ve všech pravidlech v P′ které nejsou ve tvaru Aa, kde se vyskytují na pravé straně terminály, nahradíme tyto terminály a za nové non-terminály A′ a přidáme pravidlo A′ → a (tj. nepovolená pravidla s terminály na pravé straně upravíme tak, že terminál nahradíme nonterminálem, který se přepisuje na původní terminál)

Greibachové normální forma (GNF)

Greibach normal form

Převod vlastní gramatiky bez levé rekurze (N, Σ, P, S) na gramatiku v GNF (N′, Σ, P′, S′):

  1. Seřadíme všechny nonterminály tak, aby pravá strana žádného přepisovacího pravidla nezačínala nonterminálem, který je v pořadí před přepisovaným nonterminálem. (v podstatě stejná pořadí v jakém máme nonterminály během algoritmu odstranění levé rekurze): N = {A₁, A₂, …, Aₙ}
  2. Postupně pro všechny nonterminály Aᵢ od Aₙ₋₁ sestupně po A₁:
    1. Pro každé pravidlo AᵢAjα:
      1. Odstraň toto pravidlo
      2. Pro všechna Aj-pravidla (Ajαβ) vytvoř nová pravidla ve tvaru Aᵢβα (tj. všechna pravidla jejichž pravé strana začíná nonterminálem rozepíšeme tento nonterminál na všechny možnosti na jaké jej lze přepsat)
    2. Po dokončení tohoto kroku všechny pravidla mají pravou stranu začínající terminálem.
    3. Ve všech pravidlech v P′ ve kterých se na pravé straně vyskytují terminály na jiné než první pozici nahradíme tyto terminály a za nové non-terminály A′ a přidáme pravidlo A′ → a (tj. nepovolená pravidla s terminály na pravé straně upravíme tak, že terminál nahradíme nonterminálem, který se přepisuje na původní terminál)