Analyzátor rekurzivního sestupu - Recursive descent parser
Ve výpočetní techniky , je rekurzivní sestup analyzátor je druh shora dolů analyzátor postavený ze sady vzájemně rekurzivní postupů (nebo non-rekurzivní ekvivalentu), kde každý takový postup provádí jednu z nonterminálů z gramatiky . Struktura výsledného programu tedy úzce odráží strukturu rozpoznávané gramatiky.
Prediktivní parser je rekurzivní sestup analyzátor, který nevyžaduje ústupek . Prediktivní analýza je možná pouze pro třídu LL ( k ) gramatik, což jsou bezkontextové gramatiky, pro které existuje kladné celé číslo k, které umožňuje syntaktickému analyzátoru sestupu rozhodnout, kterou produkci použít, zkoumáním pouze následujících k tokenů k vstup. Gramatiky LL ( k ) proto vylučují všechny nejednoznačné gramatiky i všechny gramatiky, které obsahují levou rekurzi . Libovolnou bezkontextovou gramatiku lze transformovat na ekvivalentní gramatiku, která nemá levou rekurzi, ale odstranění levé rekurze ne vždy přináší gramatiku LL ( k ). Prediktivní analyzátor běží v lineárním čase .
Rekurzivní sestup se zpětným sledováním je technika, která určuje, kterou produkci použít, a to postupně zkoušením každé produkce. Rekurzivní sestup se zpětným sledováním není omezen na gramatiky LL ( k ), ale není zaručeno jeho ukončení, pokud gramatika není LL ( k ). I když se ukončí, analyzátory, které používají rekurzivní sestup se zpětným sledováním, mohou vyžadovat exponenciální čas .
Ačkoli jsou prediktivní analyzátory široce používány a jsou často vybírány při ručním psaní syntaktického analyzátoru, programátoři často upřednostňují použití syntaktického analyzátoru založeného na tabulkách vytvořeného generátorem syntaktického analyzátoru , a to buď pro jazyk LL ( k ), nebo pomocí alternativního syntaktického analyzátoru, například LALR nebo LR . To platí zejména v případě, že gramatika není ve formě LL ( k ) , protože jde o transformaci gramatiky na LL, aby byla vhodná pro prediktivní analýzu. Prediktivní analyzátory lze také generovat automaticky pomocí nástrojů, jako je ANTLR .
Prediktivní parsery lze zobrazit pomocí přechodových diagramů pro každý nekoncový symbol, kde jsou okraje mezi počátečním a konečným stavem označeny symboly (terminály a nekoncové) na pravé straně produkčního pravidla.
Příklad analyzátoru
Následující EBNF like gramatiky (pro Niklaus Wirth je PL / 0 programovacího jazyka, z Algoritmy + datové struktury = Programy ) je v LL (1) tvaru:
program = block "." .
block =
["const" ident "=" num {"," ident "=" num} ";"]
["var" ident {"," ident} ";"]
{"procedure" ident ";" block ";"} statement .
statement =
ident ":=" expression
| "call" ident
| "begin" statement {";" statement } "end"
| "if" condition "then" statement
| "while" condition "do" statement .
condition =
"odd" expression
| expression ("="|"#"|"<"|"<="|">"|">=") expression .
expression = ["+"|"-"] term {("+"|"-") term} .
term = factor {("*"|"/") factor} .
factor =
ident
| number
| "(" expression ")" .
Terminály jsou vyjádřeny v uvozovkách. Každý neterminál je definován pravidlem v gramatice, kromě ident a number , u nichž se předpokládá, že jsou implicitně definovány.
C implementace
Co bude následovat, je implementace rekurzivní sestup analyzátor při výše jazyka C . Analyzátor načte zdrojový kód a ukončí se chybovou zprávou, pokud se kód nepodaří analyzovat. Pokud kód správně analyzuje, ukončí se tiše.
Všimněte si, jak blízko prediktivní analyzátor níže zrcadlí gramatiku výše. V gramatice je postup pro každého neterminálu. Parsování sestupuje způsobem shora dolů, dokud nebude zpracován konečný neterminál. Fragment programu závisí na globální proměnné sym , která obsahuje aktuální symbol ze vstupu, a funkci nextsym , která při volání aktualizuje sym .
Implementace funkcí nextsym a error jsou pro jednoduchost vynechány.
typedef enum {ident, number, lparen, rparen, times, slash, plus,
minus, eql, neq, lss, leq, gtr, geq, callsym, beginsym, semicolon,
endsym, ifsym, whilesym, becomes, thensym, dosym, constsym, comma,
varsym, procsym, period, oddsym} Symbol;
Symbol sym;
void nextsym(void);
void error(const char msg[]);
int accept(Symbol s) {
if (sym == s) {
nextsym();
return 1;
}
return 0;
}
int expect(Symbol s) {
if (accept(s))
return 1;
error("expect: unexpected symbol");
return 0;
}
void factor(void) {
if (accept(ident)) {
;
} else if (accept(number)) {
;
} else if (accept(lparen)) {
expression();
expect(rparen);
} else {
error("factor: syntax error");
nextsym();
}
}
void term(void) {
factor();
while (sym == times || sym == slash) {
nextsym();
factor();
}
}
void expression(void) {
if (sym == plus || sym == minus)
nextsym();
term();
while (sym == plus || sym == minus) {
nextsym();
term();
}
}
void condition(void) {
if (accept(oddsym)) {
expression();
} else {
expression();
if (sym == eql || sym == neq || sym == lss || sym == leq || sym == gtr || sym == geq) {
nextsym();
expression();
} else {
error("condition: invalid operator");
nextsym();
}
}
}
void statement(void) {
if (accept(ident)) {
expect(becomes);
expression();
} else if (accept(callsym)) {
expect(ident);
} else if (accept(beginsym)) {
do {
statement();
} while (accept(semicolon));
expect(endsym);
} else if (accept(ifsym)) {
condition();
expect(thensym);
statement();
} else if (accept(whilesym)) {
condition();
expect(dosym);
statement();
} else {
error("statement: syntax error");
nextsym();
}
}
void block(void) {
if (accept(constsym)) {
do {
expect(ident);
expect(eql);
expect(number);
} while (accept(comma));
expect(semicolon);
}
if (accept(varsym)) {
do {
expect(ident);
} while (accept(comma));
expect(semicolon);
}
while (accept(procsym)) {
expect(ident);
expect(semicolon);
block();
expect(semicolon);
}
statement();
}
void program(void) {
nextsym();
block();
expect(period);
}
Příklady
Některé generátory syntaktického analyzátoru rekurzivního sestupu:
- TMG - časný překladač - překladač používaný v 60. a na začátku 70. let
- JavaCC
- Coco / R
- ANTLR
- Spirit Parser Framework - C ++ rekurzivní generátor syntaktického analyzátoru sestupu, který nevyžaduje žádný krok před kompilací
- parboiled (Java) - rekurzivní sestupová knihovna pro analýzu PEG pro Javu
Viz také
- Kombinátor analyzátoru - funkce vyššího řádu používaná při kombinované analýze, metoda factoringu návrhů analyzátoru rekurzivního sestupu
- Analýza gramatiky výrazu - další forma představující gramatiku rekurzivního sestupu
- Analyzátor rekurzivního výstupu
- Ocasní rekurzivní analyzátor - varianta analyzátoru rekurzivního sestupu
Reference
Obecné odkazy
- Překladatelé: Principy, techniky a nástroje , první vydání, Alfred V Aho, Ravi Sethi a Jeffrey D Ullman, zejména Část 4.4.
- Modern Compiler Implementation in Java, Second Edition , Andrew Appel, 2002, ISBN 0-521-82060-X .
- Techniky rekurzivního programování , WH Burge, 1975, ISBN 0-201-14450-6
- Crafting a Compiler with C , Charles N Fischer a Richard J LeBlanc, Jr, 1991, ISBN 0-8053-2166-7 .
- Kompilace s C # a Java , Pat Terry, 2005, ISBN 0-321-26360-X , 624
- Algoritmy + datové struktury = programy , Niklaus Wirth, 1975, ISBN 0-13-022418-9
- Konstrukce kompilátoru , Niklaus Wirth, 1996, ISBN 0-201-40353-6
externí odkazy
- Úvod do syntaktické analýzy - snadno čitelný úvod do syntaktické analýzy s komplexní částí věnovanou syntéze rekurzivního sestupu
- Jak proměnit gramatiku na kód C - krátký návod k implementaci analyzátoru rekurzivního sestupu
- Analyzátor jednoduchých matematických výrazů v Ruby
- Jednoduchá syntéza shora dolů v Pythonu
- Jack W. Crenshaw: Pojďme sestavit kompilátor (1988-1995) v Pascalu s výstupem v montážním jazyce pomocí přístupu „keep it simple“
- Funkční perly: monadická analýza v Haskellu