
%{

#include <stdio.h>
#include "squid.h"

Bitmap read_bitmap_data_from_file();
Bitmap read_bitmap_data_from_filename();
extern int yylineno;

%}

%union {
  int number;
  char *string;
  enum sq_type squid_type;
  Squid squid;
}

%token <number> INT_CONST
%token <string> STR_CONST
%token <string> IDEN

%token EQEQ, LTEQ, GTEQ, NOTEQ
%token SEQUENCE, SHOW, TICK, BITMAP, TICKS, START, CALL
%token END, KILL, RETURN
%token WHILE, IF, THEN, ELSE, WAIT

%start top_level

%right '='
%left '|', '&'
%left EQEQ, LTEQ, GTEQ, '<', '>', NOTEQ
%left '+', '-'
%left '*', '/'
%left '!'

%type <squid> top_level
%type <squid> statements statement outer_exp expression
%type <squid> call_statement return_statement 
%type <squid> if_statement wait_statement kill_statement
%type <squid> show_statement tick_statement while_statement
%type <squid> optional_formals formals_list single_formal 
%type <squid> optional_actuals actuals_list single_actual

%%

top_level : statements
	    { the_program = $1; }

optional_formals : 
		   { $$ = NULL; }
		 | '(' formals_list ')'
		   { $$ = $2; }

formals_list : single_formal
	       { $$ = new_squid (sq_formals, $1, $1); }
	     | formals_list ',' single_formal
	       { $$ = $1;
	         $1->arg2->next = $3;
	         $1->arg2 = $3; }
		     
single_formal : IDEN
	        { $$ = new_squid (sq_iden, $1); }


statements :
	     { $$ = new_squid (sq_statements, NULL, NULL); }
	   | statements statement
	     { $$ = $1;
	       if ($1->arg1)
	         $1->arg2->next = $2;
	       else
	         $1->arg1 = $2;
	       $1->arg2 = $2; }
	       

statement : call_statement
          | if_statement
	  | kill_statement
	  | return_statement
	  | show_statement
	  | tick_statement
	  | wait_statement
	  | while_statement
	  | outer_exp

optional_actuals :
		   { $$ = NULL; }
	         | '(' ')'
		   { $$ = NULL; }
		 | '(' actuals_list ')'
		   { $$ = $2; }

actuals_list : single_actual
		  { $$ = new_squid(sq_actuals, $1, $1); }
	     | actuals_list ',' single_actual
		  { $$ = $1;
		    $1->arg2->next = $3;
		    $1->arg2 = $3; }

single_actual	: expression 

call_statement : CALL IDEN optional_actuals
		 { $$ = new_squid(sq_call, $2, $3); }

kill_statement : KILL expression
	         { $$ = new_squid(sq_kill, $2); }

return_statement : RETURN expression
		   { $$ = new_squid(sq_return, $2); }

show_statement : SHOW expression
	         { $$ = new_squid(sq_show, $2); }

tick_statement : TICK
	         { $$ = new_squid(sq_tick); }
	       | TICKS '(' expression ')' 
	         { $$ = new_squid(sq_ticks, $3); }

wait_statement : WAIT '(' expression ')'
	         { $$ = new_squid(sq_wait, NULL, $3); }
	       | IDEN '=' WAIT '(' expression ')'
	         { $$ = new_squid(sq_wait, $1, $5); }

while_statement : WHILE '(' expression ')' statements END
	          { $$ = new_squid(sq_while, $3, $5); }

if_statement : IF '(' expression ')' THEN statements END
	       { $$ = new_squid(sq_if, $3, $6, NULL); }
	       | IF '(' expression ')' THEN statements ELSE statements END
	       { $$ = new_squid(sq_if, $3, $6, $8); }

outer_exp : IDEN '=' expression
	    { $$ = new_squid (sq_bind, $1, $3); }
	  | IDEN '(' actuals_list ')'
	    { $$ = new_squid (sq_call, $1, $3); }
	  | IDEN '(' ')'
	    { $$ = new_squid (sq_call, $1, NULL); }
          | START IDEN optional_actuals
	    { $$ = new_squid(sq_start, $2, $3); }


expression : outer_exp
	   | INT_CONST
	     { $$ = new_squid (sq_int_const, $1); }
	   | STR_CONST
	     { $$ = new_squid (sq_str_const, $1); }
	   | IDEN
	     { $$ = new_squid (sq_iden, $1); }
	   | '(' expression ')'
	     { $$ = $2; }
	   | expression '*' expression
	     { $$ = new_squid (sq_times, $1, $3); }
	   | expression '/' expression
	     { $$ = new_squid (sq_divby, $1, $3); }
	   | expression '+' expression
	     { $$ = new_squid (sq_plus, $1, $3); }
	   | expression '-' expression
	     { $$ = new_squid (sq_minus, $1, $3); }
	   | expression '<' expression
	     { $$ = new_squid (sq_lt, $1, $3); }
	   | expression '>' expression
	     { $$ = new_squid (sq_gt, $1, $3); }
	   | expression LTEQ expression
	     { $$ = new_squid (sq_lteq, $1, $3); }
	   | expression GTEQ expression
	     { $$ = new_squid (sq_gteq, $1, $3); }
	   | expression EQEQ expression
	     { $$ = new_squid (sq_eq, $1, $3); }
	   | expression NOTEQ expression
	     { $$ = new_squid (sq_noteq, $1, $3); }
	   | expression '|' expression
	     { $$ = new_squid (sq_or, $1, $3); }
	   | expression '&' expression
	     { $$ = new_squid (sq_and, $1, $3); }
	   | '!' expression
	     { $$ = new_squid (sq_not, $2); }
           | SEQUENCE optional_formals statements END
	     { $$ = new_squid (sq_sequence, $3, $2); }
	   | BITMAP '(' STR_CONST ')'
	     { $$ = new_squid (sq_bitmap, $3, NULL); }



%%

yyerror()
{
  printf ("Urg.. parse error near line %d\n", yylineno);
  exit(1);
}

Squid new_squid (type, va_alist) va_dcl
     enum sq_type type;
{
  va_list list;
  
  Squid foo = (Squid) malloc(sizeof(struct squid));
  foo->type = type;
  va_begin (list, type);
  foo->lineno = yylineno;
  foo->arg1 = va_arg(list, Squid);
  foo->arg2 = va_arg(list, Squid);
  foo->arg3 = va_arg(list, Squid);
  foo->next = NULL;
  return foo;
}

