--- /dev/null
+%{
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include "symbol_table.h"
+%}
+
+%start Input
+%token FUNC END STRUCT VAR IF THEN ELSE WHILE DO RETURN OR NOT
+%token ID NUM ASSIGN GREATER
+
+@autoinh symbols
+
+@attributes { char *name; } ID
+@attributes { struct symbol_t *fields; struct symbol_t *symbols; } Program
+@attributes { struct symbol_t *fields; } Ids Structdef
+@attributes { struct symbol_t *pars; } Pars
+@attributes { struct symbol_t *symbols; } Funcdef Stats Bool Expr Call Lexpr Field Term Plusterm Malterm Bterm Orterm Exprs
+@attributes { struct symbol_t *in_symbols; struct symbol_t *out_symbols; } Stat
+
+@traversal @postorder t
+
+%%
+
+Input: Program
+ @{ @i @Program.symbols@ = @Program.fields@; @}
+
+ ;
+
+Program: Funcdef ';' Program
+ @{
+ @i @Program.fields@ = @Program.1.fields@;
+ @}
+
+ | Structdef ';' Program
+ @{
+ @i @Program.fields@ = table_merge(@Structdef.fields@, @Program.1.fields@, 1);
+ @i @Program.1.symbols@ = @Program.0.symbols@;
+ @}
+
+ |
+ @{ @i @Program.fields@ = new_table(); @}
+
+ ;
+
+Funcdef: FUNC ID '(' Pars ')' Stats END
+ @{ @i @Stats.symbols@ = table_merge(@Funcdef.symbols@, @Pars.pars@, 0); @}
+
+ |
+ FUNC ID '(' ')' Stats END
+ @{ @i @Stats.symbols@ = table_merge(@Funcdef.symbols@, new_table(), 0); @}
+
+ ;
+
+Structdef: STRUCT Ids END
+ @{ @i @Structdef.fields@ = @Ids.fields@; @}
+
+ ;
+
+Ids: ID Ids
+ @{ @i @Ids.fields@ = table_add_symbol(@Ids.1.fields@, @ID.name@, SYMBOL_TYPE_FIELD, 1); @}
+
+ |
+ @{ @i @Ids.fields@ = new_table(); @}
+
+ ;
+
+Pars: Pars ',' ID
+ @{ @i @Pars.pars@ = table_add_symbol(@Pars.1.pars@, @ID.name@, SYMBOL_TYPE_VAR, 0); @}
+
+ | ID
+ @{ @i @Pars.pars@ = table_add_symbol(new_table(), @ID.name@, SYMBOL_TYPE_VAR, 0); @}
+
+ ;
+
+Stats: Stat ';' Stats
+ @{
+ @i @Stat.in_symbols@ = @Stats.symbols@;
+ @i @Stats.1.symbols@ = @Stat.out_symbols@;
+ @}
+
+ |
+ ;
+
+Stat: VAR ID ASSIGN Expr
+ @{
+ @i @Stat.out_symbols@ = table_add_symbol(clone_table(@Stat.in_symbols@), @ID.name@, SYMBOL_TYPE_VAR, 0);
+ @i @Expr.symbols@ = @Stat.in_symbols@;
+ @}
+
+ | Lexpr ASSIGN Expr
+ @{
+ @i @Stat.out_symbols@ = @Stat.in_symbols@;
+ @i @Lexpr.symbols@ = @Stat.in_symbols@;
+ @i @Expr.symbols@ = @Stat.in_symbols@;
+ @}
+
+ | IF Bool THEN Stats END
+ @{
+ @i @Bool.symbols@ = @Stat.in_symbols@;
+ @i @Stats.symbols@ = @Stat.in_symbols@;
+ @i @Stat.out_symbols@ = @Stat.in_symbols@;
+ @}
+
+ | IF Bool THEN Stats ELSE Stats END
+ @{
+ @i @Bool.symbols@ = @Stat.in_symbols@;
+ @i @Stats.symbols@ = @Stat.in_symbols@;
+ @i @Stats.1.symbols@ = @Stat.in_symbols@;
+ @i @Stat.out_symbols@ = @Stat.in_symbols@;
+ @}
+
+ | WHILE Bool DO Stats END
+ @{
+ @i @Bool.symbols@ = @Stat.in_symbols@;
+ @i @Stats.symbols@ = @Stat.in_symbols@;
+ @i @Stat.out_symbols@ = @Stat.in_symbols@;
+ @}
+
+ | Call
+ @{
+ @i @Call.symbols@ = @Stat.in_symbols@;
+ @i @Stat.out_symbols@ = @Stat.in_symbols@;
+ @}
+
+ | RETURN Expr
+ @{
+ @i @Expr.symbols@ = @Stat.in_symbols@;
+ @i @Stat.out_symbols@ = @Stat.in_symbols@;
+ @}
+
+ ;
+
+Lexpr: ID
+ @{ @t check_variable(@Lexpr.symbols@, @ID.name@); @}
+
+ | Field
+ ;
+
+Expr: '-' Term
+ | Term
+ | Term Plusterm
+ | Term Malterm
+ ;
+
+Plusterm: '+' Term Plusterm
+ | '+' Term
+ ;
+
+Malterm: '*' Term Malterm
+ | '*' Term
+ ;
+
+Term: '(' Expr ')'
+ | ID
+ @{ @t check_variable(@Term.symbols@, @ID.name@); @}
+
+ | NUM
+ | Call
+ | Field
+ ;
+
+Bool: Bterm
+ | Bterm Orterm
+ | NOT Bterm
+ ;
+
+Orterm: OR Bterm Orterm
+ | OR Bterm
+ ;
+
+Bterm: Term GREATER Term
+ | Term '=' Term
+ | '(' Bool ')'
+ ;
+
+Field: Term '.' ID
+ @{ @t check_field(@Field.symbols@, @ID.name@); @}
+
+ ;
+
+Call: ID '(' Exprs ')'
+ | ID '(' ')'
+ ;
+
+Exprs: Expr
+ | Exprs ',' Expr
+ ;
+
+%%
+
+extern int yylex();
+extern int yylineno;
+
+int yyerror(char *error_text) {
+ fprintf(stderr,"Line %i: %s\n",yylineno, error_text);
+ exit(2);
+}
+
+int main(int argc, char **argv) {
+ yyparse();
+ return 0;
+}
+