Soubory lex.h, lex.cc, decl.h a expr.cc obsahují parser zjednodušeného jazyka C.
http://kmlinux.fjfi.cvut.cz/~culikzde/prekl/Comp11.tgz
nebo http://gitlab.fjfi.cvut.cz/culikzde/c-parser
Budeme zpracovávat výrazy, ktere mohou obsahovat identifikatory, cela cisla, vyrazy v zavorkach, plus a krat :
simple : identifier | number | '(' expr ')' ; mul : simple ( '*' simple )* ; expr : mul ( ( '+' | '-' ) mul )* ;
Syntakticke pravidlo zacina jmenem definovaneho neterminalu a dvojteckou :.
Retezce v uvozovkach jsou terminalni symboly.
Obycejne identifikatory predstavuji neterminalni symboly,
Svisla cara | predstavuje nebo
Zavorka s hvezickou ( )* dovoluje opakovani 0, 1, 2, … libovolne krat.
Zavorka s plusem ( )+ dovoluje opakovani 1, 2, … libovolne krat.
Zavorka s otaznikem ( )? dovoluje opakovani 0 nebo 1 krat.
Muzeme pouzivat zavorky bez nasledujici znacky ( ) vetsinou pri zapisu nekolika alternativ odelenych svislou carou.
Syntakticke pravidlo konci strednikem ;
void simple_expr (void) { if (sy==IDENT || { NextSymbol (); } else if (sy==NUM) { NextSymbol (); } else if (sy==LPAR) { NextSymbol (); expression (); CheckSymbol (RPAR); } else Error ("Syntax error in expression"); } void mul_expr (void) { simple_expr (); while (sy==ASTERISK || sy==SLASH || sy==MOD) { NextSymbol (); simple_expr (); } } void add_expr (void) { mul_expr (); while (sy==PLUS || sy==MINUS) { NextSymbol (); mul_expr (); } }
V souboru expr.cc nalezneme obdobné funkce, které navíc vytvářejí stromy reprezentující rozpoznané výrazy:
http://gitlab.fjfi.cvut.cz/culikzde/c-parser/-/blob/master/expr.cc#L909
ExprPtr simple_expr (void) { ExprPtr t1; if (sy==IDENT || { t1 = NewStr (IdentVal); NextSymbol (); } else if (sy==NUM) { t1 = NewStr (NumVal); NextSymbol (); } else if (sy==LPAR) { NextSymbol (); t1 = expression (); t1 = calc (t1, NULL, LPAR); CheckSymbol (RPAR); } else Error ("Syntax error in expression"); return t1; } ExprPtr mul_expr (void) { ExprPtr t1, t2; SYMBOL op; t1 = simple_expr (); while (sy==ASTERISK || sy==SLASH || sy==MOD) { op = sy; NextSymbol (); t2 = simple_expr (); t1 = calc (t1, t2, op); } return t1; } ExprPtr add_expr (void) { ExprPtr t1, t2; SYMBOL op; t1 = mul_expr (); while (sy==PLUS || sy==MINUS) { op = sy; NextSymbol (); t2 = mul_expr (); t1 = calc (t1, t2, op); } return t1; }
Pomocna funkce calc vytvari novy uzel stromu. Napriklad
t3 = calc (t1, t2, op);
Ulozi do t3 ukazatel na novy uzel, ktery ma podstromy t1 a t2
op | .------. | | t1 t2
Funkce add_expr postupne vytvari strom z multiplikativnich vyrazu.
Pokud mame na vstupu
A + B - C
Funkce add_expr vytvori strom
"-" | .------. | | "+" C | .------. | | A B
Obrazky: 2. kapitola, stranky 9 a 10 http://inf.ethz.ch/personal/wirth/CompilerConstruction/CompilerConstruction1.pdf
Pripadne dalsi informace: kapitoly 4.1 a 4.2