%{ /* Prvi deo prvog dela ove datoteke se doslovno prenosi na pocetak y.tab.c fajla, slicno kao i kod lex-a Ovde ukljucujemo neka zaglavlja, definisemo funkciju yyerror i deklarisemo yylex sto je obavezno */ #include #include #include int yyerror(char *str) { fprintf(stderr, "Pojavila se greska: %s\n", str); exit(EXIT_FAILURE); } int yylex(); %} /* Navodimo sve tokene (osim onih jednokarakterskih) kako bi yacc znao sta su neterminali a sta terminali (tokeni) */ %token num /* Kako smo koristili viseznacnu gramatiku da bi razresili shift-reduce konflikte koji bi se javili pri prevodjenju, definisemo asocijativnost i prioritet sledecih tokena */ %left '+' '-' %left '*' '/' %left UMINUS %% /* uveli smo novi startni simbol kako bi nam se ispisala vrednos izraza */ E_P : E { printf("Vrednost izraza je %d\n", $1); } ; /* koristili smo viseznacnu gramatiku i za svako reduce pravilo smo definisali akcije Svaki token i svaki neterminal imaju vrednost yylval koja je njema pridruzena Po default-u ova vrednost je tipa int $$ - vrednost desne stane pravila $i - vrednost i-tog tokena na desnoj strani pravila */ E : E '+' E { $$ = $1 + $3; } | E '-' E { $$ = $1 - $3; } | E '*' E { $$ = $1 * $3; } | E '/' E { if ($3 == 0) yyerror("Deljenje sa nulom"); $$ = $1 / $3; } | '(' E ')' { $$ = $2; } /* Kako unarni minus ima veci prioritet i od +, -, * i / Uveli smo dodatni "lazni" token UMINUS sa vecim prioritetom, a za nas minus koji se pojavljuje u pravilima preciziramo da ima asocijativnos i prioritet kao UMINUS */ | '-' E %prec UMINUS { $$ = -$2; } | num { $$ = $1; } ; %% /* Leksicki analizator */ int yylex() { int ch = getchar(); switch(ch) { case '+': return '+'; case '*': return '*'; case '-': return '-'; case '/': return '/'; case '(': return '('; case ')': return ')'; case '\n': case EOF: return 0; } if (isdigit(ch)) { yylval = ch-'0'; while (isdigit(ch=getchar())) yylval = yylval*10+ch-'0'; ungetc(ch, stdin); return num; } yyerror("Greska pri leksickoj analizi"); return -1; } /* Main funkcija */ int main() { return yyparse(); }