Levá rekurze
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
- Pro každý neterminál :
- Opakuj, dokud iterace mění gramatiku:
- Pro každé pravidlo , je řetězec terminálů a neterminálů:
- Jestliže začíná neterminálem a :
- Nechť jsou bez jeho úvodní .
- Odstraň pravidlo .
- Pro každé pravidlo :
- Přidej pravidlo .
- Jestliže začíná neterminálem a :
- Pro každé pravidlo , je řetězec terminálů a neterminálů:
- Odstraň přímou levou rekurzi pro , jak je popsáno výše.
- Opakuj, dokud iterace mění gramatiku:
- Pro každý neterminál :
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:

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

,
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.
- ↑ Notes on Formal Language Theory and Parsing Archivováno 28. 8. 2017 na Wayback Machine., James Power, Department of Computer Science National University of Ireland, Maynooth Maynooth, Co. Kildare, Ireland.JPR02
- ↑ 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.
- ↑ 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.
- ↑ 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. Archivováno 27. 5. 2011 na Wayback Machine.
- ↑ 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]- CMU lecture on left recursion Archivováno 3. 3. 2016 na Wayback Machine.
- Practical Considerations for LALR(1) Grammars
- X-SAIGA – eXecutable SpecificAtIons of GrAmmars