===== Choose - opožděné rozhodnutí ====
Při zpracování aritmetických výrazů není vhodné vytvářet novou instanci pro každé zpracovávané pravidlo
simple_expr : identifier | number | "(" expr ")" ;
multiplicative_expr : simple_expr ( ("*"|"/") simple_expr )* ;
additive_expr : multiplicative_expr ( ("+"|"-") multiplicative_expr )* ;
expr : additive_expr ( "=" expr )? ;
Pokud např. zpracováváme výraz A + B - C, \\
zajímají nás uzly odpovídající aditivnímu výrazu a listy s idetifikátory.
Uzly, které neskladují žádnou aritmetickou operaci, většinou znepřehledňují strom.
==== Klíčové slovo choose před typem pravidla ====
additive_expr :
multiplicative_expr
(
( '+' |
'-' )
right:multiplicative_expr
)* ;
* Před typem pravidla uvedeme klíčové slovo **choose**.
* Popis pravidla začneme neterminálním symbolem, který bude výsledkem pokud nenastane následující varianta v závorkách
* Varianta v závorkách ** ( )? ** nebo **()* **
* Pokud varianta nastane, každé opakování vytvoří novou instanci ** **
* Původní výsledek nebo předchozí varianta se uloží jako položka nové instance ** **
* Uvnitř varianty může být další větvení, ale vše se již ukládá do vytvořené instance
* Pokud některé alternativy obsahují jen terminály např. ** ("+"|"-") **, můžeme nastavit nějakou položku na hodnotu výčtového typu ** **
==== Požadavky na použité typy ====
* Typ úvodního neterminálu musí být odvozen z typu pravidla
* Typ použitý uvniř varianty také musí být odvozen z typu pravidla
==== Vygenerovaná metoda syntaktického analyzátoru ===
def parse_additive_expr (self) :
result = self.parse_multiplicative_expr ()
while self.tokenText == "+" or self.tokenText == "-" :
store = result
result = CmmAddExpr ()
result.left = store
if self.tokenText == "+" :
self.check ("+")
result.kind = result.addExp
elif self.tokenText == "-" :
self.check ("-")
result.kind = result.subExp
else :
self.error ("Unexpected token")
result.right = self.parse_multiplicative_expr ()
return result
Pokud bude na vstupu např. A + B - C, vznikne strom
"-"
|
.------.
| |
"+" C
|
.------.
| |
A B
Do proměnné **result** se nejprve voláním **parse_multiplicative_expr** uloží **A**.
Jelikož následuje plus, původní hodnotu **result** uschováme do proměnné **store**. \\
Do **result** uložíme nový uzel pro aritmetickou operaci typu **CmmAddExpr**. \\
Původní hodnotu (**A**) uložíme do **result.left**. \\
Nastavíme **result.kind** na **addExp** nebo **subExp**. \\
Pravý operand (**B**) uložíme do **result.right**.
Nyní se **while** cyklus opakuje.\\
Jelikož následuje minus, současný výsledek (**A+B**) uschováme, \\
a vytvoříme novou instanci, tentokrát pro minus.
Pokud nenásleduje další plus nebo minus, tak funkce skončí a výsledkem bude načrtnutý strom. \\
Můžete porovnat s úvodní kapitolou [[prekl::expr|syntaktická analýza výrazů]].
==== Vygenerovaná metoda pro tisk zdrojového textu ====
Metoda pro tisk nejprve vyzkouší zda parametr není typem pro naší variantu **CmmAddExpr**.
Pro tisk levého parametru rekurzivně použije stejnou metodu.
Nakonci metody je //else// pro případ, že naše varianta nenastala.
def send_additive_expr (self, param) :
if isinstance (param, CmmAddExpr) :
self.send_additive_expr (param.left)
if param.kind == param.addExp :
self.send ("+")
elif param.kind == param.subExp :
self.send ("-")
self.send_multiplicative_expr (param.right)
else :
self.send_multiplicative_expr (param)