Levá rekurze

Z Wikipedie, otevřené encyklopedie
Skočit na navigaci Skočit na vyhledávání

Levá rekurze v teorii formálních jazyků v matematické informatice je speciální případ rekurze, kdy lze určitý neterminální symbol přepsat v jednom nebo více krocích na řetězec, který obsahuje stejný neterminální symbol. O levou rekurzi se jedná, pokud je příslušný neterminál na začátku výsledného řetězce. Lze také říct, že určitý řetězec je rozpoznán jako část jazyka tak, že se skládá z řetězce z téhož jazyka (vlevo) a zbytku, sufixu (vpravo). Například ve výseku gramatiky pro aritmetický výraz: , , , je neterminál E zleva rekurzivní. Výraz je rozpoznán jako součet, protože jej lze rozložit na součet a sufix .

V termínech bezkontextových gramatik neterminální symbol obsahuje levou rekurzi, jestliže první symbol v jednom z jeho pravidel je samotný (v případě přímé levé rekurze) nebo lze získat řetězec obsahující tentýž symbol nějakou posloupností substitucí (v případě nepřímé levé rekurze).

Definice[editovat | editovat zdroj]

Gramatika obsahuje levou rekurzi právě tehdy, když existuje neterminální symbol , ze kterého lze odvodit větnou formu, která začíná původním neterminálem.[1] Symbolicky,

,

kde je operace provedení jedné nebo více substitucí a je libovolný řetězec terminálních a neterminálních symbolů.

Přímá levá rekurze[editovat | editovat zdroj]

O přímou levou rekurzi se jedná, když podmínky z definice rekurze jsou splněny již jedinou substitucí. Vyžaduje pravidlo tvaru

kde je řetězec neterminálů a terminálů. Například pravidlo

je přímo s levou rekurzí. Analyzátor s rekurzivním sestupem zleva doprava pro toto pravidlo může být následující:

funkce Expression()
{
    Expression();  match('+');  Term();
}

Tento kód způsobí při svém provedení nekonečnou rekurzi.

Nepřímá levá rekurze[editovat | editovat zdroj]

O nepřímou levou rekurzi se jedná, když jsou podmínky z definice rekurze splněny až při použití více než jednoho přepsání. Má za následek sada pravidel následující vzorek

kde jsou řetězce, které všechny mohou dávat prázdný řetězec, a jsou libovolné řetězce. Derivace

pak dává jako první symbol v poslední větné formě.

Odstraňování levé rekurze[editovat | editovat zdroj]

Levá rekurze často představuje problém pro analyzátory, buď protože vede k nekonečné rekurzi (v případě většiny analyzátorů shora dolů) anebo protože očekávají pravidla v normální formě, která rekurzi zakazuje (jako v případě mnoha analyzátorů zdola nahoru, včetně CYK algoritmu). Proto se gramatiky často upravují, aby levou rekurzi neobsahovaly.

Odstraňování přímé levé rekurze[editovat | editovat zdroj]

Následující algoritmus slouží pro odstranění přímé levé rekurze. Existuje několik jeho vylepšení.[2] Pro každý neterminál s levou rekurzí, zahodíme všechna pravidla tvaru a ostatní pravidla tvaru:

kde:

  • jsou neprázdné řetězce neterminálů a terminálů a
  • jsou řetězce neterminálů a terminálů, které nezačínají symbolem .

nahradíme dvěma množinami pravidel, jednou se symbolem na levé straně:

a druhou s přidaným neterminálním symbolem (obvykle nazývaným „zakončení“ nebo "zbytek"):

Uvedený postup se opakuje, dokud nezůstává žádná přímá levá rekurze.

Jako příklad uvažujme sadu pravidel

kterou lze přepsat, aby se zabránilo levé rekurzi jako

Odstraňování veškeré levé rekurze[editovat | editovat zdroj]

Topologickým setříděním neterminálů lze výše uvedený postup rozšířit na odstraňování nepřímé levé rekurze:

Vstup Gramatika: množina neterminálů a jejich pravidel
Výstup Upravená gramatika generující stejný jazyk, ale bez levé rekurze
  1. Pro každý neterminál :
    1. Opakuj, dokud iterace mění gramatiku:
      1. Pro každé pravidlo , je řetězec terminálů a neterminálů:
        1. Jestliže začíná neterminálem a :
          1. Nechť jsou bez jeho úvodní .
          2. Odstraň pravidlo .
          3. Pro každé pravidlo :
            1. Přidej pravidlo .
    2. Odstraň přímou levou rekurzi pro , jak je popsáno výše.

Všimněte si, že tento algoritmus je velmi citlivý na pořadí neterminálů; jeho optimalizace se často zaměřují na správný výběr tohoto řazení.

Skryté nástrahy[editovat | editovat zdroj]

Ačkoli výše uvedené transformace nemění generovaný jazyk, mohou měnit derivační strom, na kterém závisí struktura řetězce. Existují postupy, které pomocí stromových transformací mohou vést k původním výsledkům. Při vynechání tohoto kroku však rozdíly mohou změnit sémantiku analýzy.

Obzvláště zranitelná je asociativita; zleva asociativní operátory jsou do nové gramatiky převedeny jako zprava asociativní. Pokud například uvažujeme následující gramatiku:

standardní transformace pro odstranění levé rekurze dává následující:

Syntaktická analýza řetězce „1 - 2 - 3“ LALR analyzátorem podle původní gramatiky (LALR analyzátor umožňuje analýzu gramatik s levou rekurzí) dává derivační strom:

Analýza opakovaného odčítání s levou rekurzí

Tento derivační strom seskupuje termy odleva, což dává správnou sémantiku (1 - 2) - 3.

Syntaktická analýza podle upravené gramatiky dává derivační strom

Analýza opakovaného odčítání obsahující pravou rekurzi

,

který je při správné interpretaci 1 + (-2 + (-3)) také správný, ale méně věrný vstupu, a implementace některých operátorů může být mnohem obtížnější. Všimněte si, že se termy vpravo vyskytují hlouběji ve stromě, podobně jako v gramatice s pravou rekurzí jejich úpravou na 1 - (2 - 3).

Ošetření levé rekurze při analýze shora dolů[editovat | editovat zdroj]

Formální gramatika, která obsahuje levou rekurzi, nemůže být analyzována LL(k)-analyzátorem nebo jiným naivním analyzátorem s rekurzivním sestupem, pokud není zkonvertována na tvar slabě ekvivalentní gramatiky s pravou rekurzí. Naproti tomu, levá rekurze je upřednostňovaná pro LALR analyzátory, protože vede k menšímu využívání zásobníku než pravá rekurze. Rafinovanější analyzátory shora dolů však mohou implementovat obecné bezkontextové gramatiky pomocí omezení. V roce 2006 popsali Frost a Hafiz algoritmus, který je použitelný pro nejednoznačné gramatiky s přímou levou rekurzí.[3] Tento algoritmus v roce 2007 rozšířil Frost, Hafiz a Callaghan na úplný algoritmus analýzy, který dovoluje nepřímou i přímou levou rekurzi v polynomiálním čase a pro vysoce nejednoznačné gramatiky generuje kompaktní reprezentaci polynomiální velikosti pro potenciálně exponenciální funkci počtu stromů analýzy.[4] Autoři pak implementovali algoritmus jako sadu kombinátorů syntaktických analyzátorů napsaný v jazyce Haskell.[5]

Odkazy[editovat | editovat zdroj]

Reference[editovat | editovat zdroj]

V tomto článku byl použit překlad textu z článku Left recursion na anglické Wikipedii.

  1. Notes on Formal Language Theory and Parsing, James Power, Department of Computer Science National University of Ireland, Maynooth Maynooth, Co. Kildare, Ireland.JPR02
  2. MOORE, Robert C. Removing Left Recursion from Context-Free Grammars. In: 6th Applied Natural Language Processing Conference. [s.l.]: [s.n.], květen 2000. Dostupné online.
  3. FROST, R. A New Top-Down Parsing Algorithm to Accommodate Ambiguity and Left Recursion in Polynomial Time.. ACM SIGPLAN Notices. 2006. Dostupné online. DOI:10.1145/1149982.1149988. , dostupný od autora v http://hafiz.myweb.cs.uwindsor.ca/pub/p46-frost.pdf Archivováno 8. 1. 2015 na Wayback Machine
  4. FROST, R. Modular and Efficient Top-Down Parsing for Ambiguous Left-Recursive Grammars.. In: 10th International Workshop on Parsing Technologies (IWPT), ACL-SIGPARSE. Praha: [s.n.], červen 2007. Dostupné v archivu pořízeném dne 2011-05-27.
  5. FROST, R. Parser Combinators pro Ambiguous Left-Recursive Grammars. In: 10th International Symposium on Practical Aspects of Declarative Languages (PADL), ACM-SIGPLAN. 2008. vyd. [s.l.]: [s.n.], leden 2008. Dostupné online. ISBN 978-3-540-77441-9. DOI:10.1007/978-3-540-77442-6_12. Svazek 4902.

Související články[editovat | editovat zdroj]

Externí odkazy[editovat | editovat zdroj]