===== Syntaktický analyzátor vytvářející syntaktický strom =====
==== Vstupní gramatika s atributy ====
Rozšíříme vstupní gramatiku o atributy popisující ukládání informací do syntaktického stromy.
Před jménem neterminálu může být uvedeno jméno proměnné, do které bude uložen příslušný syntaktický podstrom.
else_code : stat
Za jménem pravidla může být identifikátor třídy pro ukládání dat z jednoho uzlu syntaktického stromu. \\
Za identifikátorem třídy může být identfikátor nadřazené třídy, z které je první třída odvozena.
if_stat < CmmIfStat: CmmStat > : ... ;
Například pravidlo pro příkaz **if**
if_stat < CmmIfStat: CmmStat > :
"if"
"(" cond:expr ")"
then_code:stat
(
"else"
else_code:stat
)? ;
Generátor z popisu pravidla napíše deklaraci třídy pro uložení uzlu stromu odpovídajícímu pravidlu //if_stat//. \\
Předpokládejme, že pravidla //expr// a //stat// mají jako svůj typ uveden //CmmExpr// a //CmmStat//, \\
potom pokud generujeme analyzátor v jazyce C++. vznikne deklarace:
class CmmIfStat : public CmmStat
{
public:
CmmExpr * cond;
CmmStat * then_stat;
CmmStat * else_stat;
};
nebo pokud generujeme analyzátor napsaný v Pythonu
class CmmIfStat (CmmStat) :
def __init__ (self) :
super (CmmIfStat, self).__init__ ()
self.cond = None
self.then_code = None
self.else_code = None
Program pro načtení gramatiky s rošiřujícími atributy:
[[http://gitlab.fjfi.cvut.cz/culikzde/simple-view/-/blob/master/tutorial/easy-grammar/easy_grammar.py|easy_grammar.py]]
==== Vygenerovaný analyzátor ====
Analyzátor rozpoznává, zda zdrojový text na vstupu odpovídá zadané gramatice, \\
a současně vytváří syntaktický strom ze zmíněných tříd:
Generátor podle zadané gramatiky napíše třídu //Parser// implementující syntaktický analyzátor. \\
Pro jednotlivá pravidla generátor napíše metody v této třídě.
class Parser (Lexer) :
def parse_if_stat (self) :
result = CmmIfStat ()
self.storeLocation (result)
self.check ("if")
self.check ("(")
result.cond = self.parse_expr ()
self.check (")")
result.then_code = self.parse_stat ()
if self.tokenText == "else" :
self.check ("else")
result.else_code = self.parse_stat ()
return result
Metoda **parse_if_stat** vytvoří novou instanci třídy **CmmIfStat**, která bude i výsledkem této metody. \\
Do vzniklé instance uložíme informace o číslu řádky ve zdrojovém souboru, \\
//které využijeme např. při kliknutí do grafické reprezentace sybtaktického stromu a můžeme zvýraznit příslušnou zdrojovou řádku.//
Potom zkontroluje, zda na vstupu jsou terminální symboly **if** a **(**.
K zpracování výrazu zavolá metodu **parse_expr** a odkaz na podstrom popisující výraz uloží do položky **cond** ve vytvořené instanci.
Zkontroluje **)** a metoda **parse_stat** uloží odkaz na //"then"// příkaz do položky **then_code**.
Na základě [[prekl::gram_symbols|množin lexikálních symbolů]], kterými začínají jednotlivá pravidla \\
se generátor rozhodne, že musí otestovat zda následuje terminální symbol **else**.
Funkce **check ("else")** jen přeskočí symbol else, o kterém my víme, že tam bude.
**parse_stat** uloží //"else"// příkaz do položky **else_code**.
Pokud terminál **else** není přítomen, zůstane položka **else_code** nastavená na hodnotu **None**, \\
kterou tam umístil konstruktor třídu **CmmIfStat**.
Program generující syntaktický analyzátor:
[[http://gitlab.fjfi.cvut.cz/culikzde/view/-/blob/master/tutorial/easy-grammar/easy_toparser.py|easy_toparser.py]]
==== Vygenerovaný analyzátor v jazyce C++ ====
Případně generátor syntaktického analyzátoru v jazyce C++
[[http://gitlab.fjfi.cvut.cz/culikzde/view/-/blob/master/tutorial/easy-grammar/easy_cparser.py|easy_cparser.py]]
CmmIfStat * CmmParser::if_stat ()
{
CmmIfStat * result = new CmmIfStat;
match (KEYWORD_if);
match (LPAREN);
result->cond = expr ();
match (RPAREN);
result->then_stat = stat ();
if (isSymbol (KEYWORD_else))
{
match (KEYWORD_else);
result->else_stat = stat ();
}
return result;
}
==== Generování syntaktických analyzátorů ====
Jednoduché grafické rozhranní pro generování syntaktických analyzátorů:
[[http://gitlab.fjfi.cvut.cz/culikzde/view/-/blob/master/tutorial/easy-grammar/easy_view.py|easy_view.py]]
{{prekl:easy_view.png}}
{{prekl:generovani.png?800}}