%{

%}

%union {
  char *id;
  int number;
}

%token IDENTIFIER NUMBER

%token MODULE BEGIN END ARRAY OF POINTER TO RECORD 
%token TRUE FALSE
%token IF THEN ELSE WHILE DO RETURN
%token INTEGER BOOLEAN 
%token TYPE VAR PROCEDURE 

%left '<' '=' '>'
%left '+' '-' OR
%left '*' AND
%left NOT
%left '(' ')'

%%

program: MODULE IDENTIFIER ';' declarations 
	 BEGIN statementlist END IDENTIFIER '.' 
	;

/*  These rules aren't used, may as well just get them out of here.
comp_type: '[' NUMBER '.' '.' NUMBER ']' 
  |        ARRAY typedenoter OF typedenoter
  |	   POINTER TO typedenoter
  |        RECORD rec_entries END
  ;
rec_entries: rec_entries ';' rec_entry
	|    rec_entry
	;

rec_entry: id_list : typedenoter
	;

id_list: id_list ';' IDENTIFIER
   |	 IDENTIFIER
   ;
*/

declarations: declarations ';' declaration
	|     declaration
	;

declaration:  type_decl
	|     var_decl
	|     proc_decl
	;

type_decl:  TYPE type_tail
	;

type_tail:  type_tail IDENTIFIER '=' typedenoter ';'
	|   IDENTIFIER '=' typedenoter ';'
	;

var_decl: VAR var_tail
	;

var_tail: var_tail var_id_list ':' typedenoter ';'
	| var_id_list ':' typedenoter ';'
	;

var_id_list: var_id_list ',' IDENTIFIER
	|    IDENTIFIER
	;

proc_decl: IDENTIFIER '(' ')' proc_type ';' declarations 
	   BEGIN statementlist END IDENTIFIER ';'
	;

proc_type: ':' typedenoter
	|
	;

typedenoter: IDENTIFIER
	|    INTEGER
	|    BOOLEAN
	;

statementlist: statementlist ';' statement
	|      statement
	;

statement:  assign_statement
	|   if_then_else_statement
	|   while_do_statement
	|   proc_statement
	|   return_statement
	;

assign_statement: IDENTIFIER ':' '=' expression
	;

if_then_else_statement: 
	IF expression THEN statementlist else_part END
	;

else_part: ELSE statementlist
	|  
	;

while_do_statement:
	WHILE expression DO statementlist END
	;

proc_statement: IDENTIFIER '(' ')'
	;

return_statement:  RETURN return_tail
	;
	
return_tail:  expression
	|
	;

expression: expression rel_op sign_part exp_rest
	|   sign_part exp_rest
	;

rel_op:   '<'
	| '='
	| '>'
	;

sign_part: '+'
	|  '-'
	|
	;

exp_rest: exp_rest bin_op not_list term
	| not_list term
	;

bin_op:   '*'
	| '+'
	| '-'
	| OR
	| AND
	;

not_list: not_list NOT
	| NOT
	;

term:     TRUE
	| FALSE
	| NUMBER
	| IDENTIFIER
	| IDENTIFIER '(' ')'
	| '(' expression ')'
	;

%%

