

%{
#include "defs.h"
#include "lex.yy.c"
#include "ext.h"
#define YYDEBUG
#define MAXIDLIST 200

int   i1,i2,i3,i4,i5,i6,i7,i8,i9;
double f1,f2,f3,f4,f5,f6,f7,f8,f9,d1;
char  *c1,*c2,*c3;
Tree	tp1,tp2,tp3,tp4,tp5,tp6,tp7,tp8,tp9;
SYMBOL	*sp1,*sp2,*sp3,*sp4,*sp5,*sp6,*sp7,*sp8,*sp9;
int 	idcount =0;	
char	*idlist[MAXIDLIST];  
int     interactive;
char    str[200];
char    strp;
int     flerror;      /* set if there was an error during parsing */
int	level=0;        /* keeps track whether we are in a structure*/
%}

%left  <ival>LOWPRIO
%left  <ival> '='
%left  <ival>T_OR
%left  <ival>T_AND
%left  <ival>  T_EQU UNEQU
%left  <ival>'<' '>'  LESSEQU GTREQU
%left  <ival>'+' '-'
%left  <ival>'*' '/'
%left  <ival>T_POW
%left  <ival> CASTTOKEN
%token <ival>FLT CTOO CTOL OTOL OTOC LTOO LTOC
%token <ival>ID NUM T_NOT IF ELSE FOR WHILE 
%token <ival>T_TRUE T_FALSE STRING 
%type  <trees> stml stmt rstmt bexp expl exp str
%type  <str>  id 

%%
prg:	stml 		{program = $1;return (0);}
	;

stml :	    stmt          {$$ = $1;}		
	|   stml  stmt	  {$$ = tseq($1,$2);}
	|   stmt ";"          {$$ = $1;}		
	|   stml  stmt ";"  {$$ = tseq($1,$2);}
	;

stmt:	    FLT idl 		{ declare(T_FLOAT);idcount=0;}
	|   rstmt		{
				if (level==0) 
					$$ = go($1); 
				else    $$ = $1;
				}
	|   IF level bexp stmt 		{
					level--;
					$$ = go(tif($3,$4));
					}
	|   IF level bexp stmt ELSE stmt {
					level--;
					$$ = go(tifelse($3,$4,$6));
					} 
	|   WHILE level bexp stmt	{
					level--;
					$$ = go(twhile($3,$4));
					} 
	|   FOR level '(' stmt ';' bexp ';' stmt ')' stmt {
					level--;
					$$ = go(tfor($4,$6,$8,$10));
					}
	|   '{' stml '}'		{$$ = $2;} 
	|   error FLT			{flerror = 1;$$=tnoop();}
	|   error IF			{flerror = 1;$$=tnoop();}
	|   error WHILE			{flerror = 1;$$=tnoop();}
	|   error FOR			{flerror = 1;$$=tnoop();}
	|   error '{'			{flerror = 1;$$=tnoop();}
	|   error ELSE			{flerror = 1;$$=tnoop();}
	|   error ';'			{flerror = 1;$$=tnoop();}
	;
	/*  statements that can return a value */
level:                          {
					level++;
				}

rstmt:	id  '=' exp		{
					sp1=lookup($1);
					if (sp1==NULL) {
			   sprintf(str,"note: %s has been auto declared",$1);
				sp1=install($1,S_GLOBAL,T_FLOAT);
	      				   yyerror (str); 	
					}
					$$ = tstore(tname(sp1),$3); 
				}
	|   id '(' expl ')' 	 	{$$ = tcall ($3,$1);}	
	;


idl:	    id				{ idlist[idcount++]=$1;}
	|   idl ',' id			{ idlist[idcount++]=$3;}
	;

id:	    ID				{ $$ = strsave(yytext);}
	;	

expl:       exp			{$$ = targ(tnoargs(),$1);}
	|   expl ',' exp	{ $$ = targ($1,$3); }
/* NOTE: on casting of strings:  first, cast char* into an int, then
cast the int into a double(not float).  To convert back, do just the
opposite */
	|   str	 	{ 
			$$ = targ(tnoargs(),$1);
			}
	|   expl ',' str    {
			$$ = targ($1,$3);
			}
	|			{$$ = tnoargs();}
	;
str:	   STRING	{
			c1 = yytext + 1;
			c1[strlen(c1)-1]= '\0';
/* Here we do some weird conversion from char* to int to double.
 * It is a hack that allows to pass strings to cmix functions, 
 * in a way, that only the function needs to know about it.
 * It very likely to be machine dependent, so you might have to hack it
 * if it doesn't work on your system.  If you do, send me mail. ***lars.
 * (It might help to look at the assembler output produced by cc)
 */
			i1 =  strsave(c1);
			d1 = (double) i1;
			$$ = tconstf(d1);
			}	
	;

bexp:	    exp	    %prec LOWPRIO           { $$ = $1;}
	|   T_NOT bexp   %prec UNEQU { $$ = tnot($2);	}           
	|   bexp T_AND bexp   { $$ = tcand($1,$3);   }
	|   bexp T_OR  bexp   { $$ = tcor($1,$3);  } 
		/* note the comparison of booleans */
	|   bexp T_EQU bexp   { $$ = trel(EQ,$1,$3); }
	|   exp '<' exp   { $$ = trel(LT,$1,$3); }
	|   exp '>' exp   { $$ = trel(GT,$1,$3);}
	|   exp UNEQU exp   { $$ = trel(NEQ,$1,$3);}
	|   exp LESSEQU exp { $$ = trel(LEQ,$1,$3); } 
	|   exp GTREQU  exp { $$ = trel(GEQ,$1,$3); }
	|   T_TRUE  {
			$$ = trel (EQ,tconstf(1.0),tconstf(1.0));
		    }
	|   T_FALSE {
			$$ = trel (NEQ,tconstf(1.0),tconstf(1.0));
		    }
        ;	

exp:	    exp T_POW exp     { $$ = top(POW,$1,$3); }
	|   rstmt	      { $$ = $1;}
	|   exp '*' exp     { $$ = top(MUL,$1,$3); }
	|   exp '/' exp     { $$ = top(DIV,$1,$3); }
	|   exp '+' exp     { $$ = top(PLUS,$1,$3); }
	|   exp '-' exp     { $$ = top(MINUS,$1,$3); }
	|   '(' bexp ')' { $$ = $2;}
	|   NUM  {
			sscanf(yytext,"%f",&f1);
			$$ = tconstf(f1);
	           }
	|   '-' NUM     %prec CASTTOKEN {
			sscanf(yytext,"%f",&f1);
			$$ = tconstf(-f1);
	           }
	|   id    {
		
		sp1=lookup($1);
		if (sp1==NULL) {
		  sprintf(str,"error: %s is not declared",$1);
			yyerror (str); 	
		  $$ = tconstf(0.0);
		}else  $$ = tname(sp1);
	}
		
		
	;




%%

declare(type)
int   type;
{

int  i1;
SYMBOL  *sp1;

  for (i1=0;i1<idcount;i1++) {

	sp1 = lookup (idlist[i1]);
	if (sp1 != NULL) {
		sprintf(str,"warning: variable redefined: %s",idlist[i1]);
/*  note this handling may be illegal in arbitrary scoping */
		sp1->type = type;
		yyerror(str);
	}
	else install(idlist[i1],S_GLOBAL,type);
  }
}	

Tree go (t1)
Tree t1;
{
	if (interactive && level==0)   exct(t1);
	if (interactive && level==0)   free_tree(t1);
	return (t1);
}
