===== Syntaktická analýza výrazů =====
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 **;**
===== Funkce rozpoznavájící jednoduché výrazy =====
void simple_expr (void)
{
if (sy==IDENT)
{
NextSymbol ();
}
else if (sy==NUM)
{
NextSymbol ();
}
else if (sy==LPAR)
{
NextSymbol ();
add_expr ();
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 ();
}
}
===== Funkce vytvářející syntaktické stromy =====
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