Levá rekurze
From Wikipedia, the free encyclopedia
Remove ads
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).
Remove ads
Definice
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
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
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ě.
Remove ads
Odstraňování levé rekurze
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
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
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í.
Remove ads
Skryté nástrahy
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).
Remove ads
Ošetření levé rekurze při analýze shora dolů
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]
Remove ads
Odkazy
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads