Klíčové slovo select před typem pravidla.
Pravidlo je tvořeno výběrem z několika jednoduchých alternativ,
které mají výsledný typ odvozený z typu zmíněného pravidla.
stat < select TStat > : while_stat | if_stat | compound_stat | simple_stat | empty_stat ;
Vytvořená metoda parse_stat sama nevytváří novou instanci,
ale použije instanci dodanou metodou parse_while_stat, parse_if_stat, …
def parse_stat (self) : if self.tokenText == "while" : result = self.parse_while_stat () elif self.tokenText == "if" : result = self.parse_if_stat () elif self.tokenText == "{" : result = self.parse_compound_stat () elif self.token == self.identifier or self.token == self.number or self.tokenText == "(" : result = self.parse_simple_stat () elif self.tokenText == ";" : result = self.parse_empty_stat () else : self.error ("Unexpected token") return result
Metoda pro tisk zdrojového textu uloženého v syntaktickém stromu send_stat
otestuje skutečný typ parametru a zavolá send_while_stat, …
def send_stat (self, param) : if isinstance (param, TWhileStat) : self.send_while_stat (param) elif isinstance (param, TIfStat) : self.send_if_stat (param) elif isinstance (param, TCompoundStat) : self.send_compound_stat (param) elif isinstance (param, TSimpleStat) : self.send_simple_stat (param) elif isinstance (param, TEmptyStat) : self.send_empty_stat (param)
Zde jsou vygenerované třídy pro uskladnění dat:
class TStat : pass class TWhileStat (TStat) : def __init__ (self) : super (TWhileStat, self).__init__ () self.cond = None self.code = None
CmmStat * CmmParser::parse_stat () { CmmStat * result = NULL; if (isSymbol (KEYWORD_while)) result = parse_while_stat (); else if (isSymbol (KEYWORD_if)) result = parse_if_stat (); else if (isSymbol (LBRACE)) result = parse_compound_stat (); else if (TestSymbols (set_11)) result = parse_simple_stat (); else if (isSymbol (SEMICOLON)) result = parse_empty_stat (); else error ("Unexpected symbol"); return result; } const unsigned char set_11 [] = { ... };
Množina set_11 obsahuje symboly, kterými může začínat jednoduchý příkaz.
void CmmProduct::send_stat (CmmStat * item) { if (item->conv_CmmWhileStat () != NULL) send_while_stat (item->conv_CmmWhileStat ()); else if (item->conv_CmmIfStat () != NULL) send_if_stat (item->conv_CmmIfStat ()); else if (item->conv_CmmCompoundStat () != NULL) send_compound_stat (item->conv_CmmCompoundStat ()); else if (item->conv_CmmSimpleStat () != NULL) send_simple_stat (item->conv_CmmSimpleStat ()); else if (item->conv_CmmEmptyStat () != NULL) send_empty_stat (item->conv_CmmEmptyStat ()); else assert (false); }
Pro testování typu lze použít dynamic_cast.
Nebo jednoduché virtuální metody jako jsou conv_CmmIfStat, conv_CmmWhileStat
class CmmStat { // conversion functions public: virtual CmmIfStat * conv_CmmIfStat () { return NULL; } virtual CmmWhileStat * conv_CmmWhileStat () { return NULL; } }; class CmmWhileStat : public CmmStat { public: CmmExpr * cond; CmmStat * body; // conversion functions public: virtual CmmWhileStat * conv_CmmWhileStat () { return this; } };