//Compiler Project#2
//Parser
//Author:Guangming Xing
//@1
#define EXTERN extern
#include "symbtab.h"
#include "scanner.h"
#include "global.h"
#include "error.h"
#include <strstream.h>
#include <fstream.h>
extern TOKEN Token;
fstream strout;
int  type_process();
void parser();
void program();
void program_header();
Symbol  *look_up(char *,STACK *);
int type_process();
int get_label();
void block(int ,char *,int);
void print_stack(STACK *);
void declarations(int *);
void declaration(int *);
void variable_declarations(int *);
void variable_declaration(int *);
void procedure_declaration();
char * procedure_header(int *,int *);
void parameter_list();
void parameter_group();
void compound_statement();
void statement_list();
void statement();
int  expression_list(Symbol *);
int  expression(int *);
int  simple_expression(int * );
int  term(int *);
int  factor(int *);
int identifier_list(char [8][32]);
void recovery(int);//the int specifies the Error code
int match(TOKEN_TYPE tokentype);
void else_suffix(int);
void id_suffix(Symbol *);
void record_definition(int );
void array_definition(int );
int  fact_prm(Symbol *);
void current_install(Symbol *,STACK *);
void push(STACK *);
void pop(STACK *);

void parser(char *filename)
{
int fd;
struct stat buf;
int i,j;
char name[32];
Symbol *sym;
strcpy(name,filename);
i=stat(strcat(filename,".p"),&buf);
strout.open(strcat(name,".asm"),ios::out|ios::trunc);
fd=open(filename,O_RDONLY);
if(fd==-1)
{
cout<<"No such file exist"<<endl;
exit(1);
}
j=read(fd,filebuffer,buf.st_size);
filebuffer[buf.st_size]=EOF;
Next_Char();
Token=Get_Token();
//initialization
s.current_index=0;
for(i=0;i<8;i++)
s.S[i]=(Symbol *)NULL;

sym=new Symbol;
strcpy(sym->name,"integer");
sym->type=0;//it is a type
sym->type_entry=0;//the position in type table is 0
current_install(sym,&s);

sym=new Symbol;
strcpy(sym->name,"real");
sym->type=0;//it is a type
sym->type_entry=1;//the position in type table is 0
current_install(sym,&s);

sym=new Symbol;
strcpy(sym->name,"readln");
sym->type=2;//it is a procedure 
sym->type_entry=1;//how many parameters
sym->paralist[0].passingconvention=1;//call by refreence
sym->paralist[0].type=98;//it can be any type
current_install(sym,&s);

sym=new Symbol;
strcpy(sym->name,"write");
sym->type=2;//it is a procedure 
sym->type_entry=1;//how many parameters
sym->paralist[0].passingconvention=0;//call by value
sym->paralist[0].type=99;//it can be any type
current_install(sym,&s);

sym=new Symbol;
strcpy(sym->name,"writeln");
sym->type=2;//it is a procedure 
sym->type_entry=0;//how many parameters
current_install(sym,&s);

//preload the type table
typetab[0].type=0;//this is integer
typetab[1].type=1;//this is real
typetab[2].type=2;//this is bool
typetab[3].type=3;//this is String

//4 is an array 5 is a record

type_index=4;//there are four preloaded so the index for the next one
//will be 4

while(Token.Token_Type!=ENDFILE)
program();

strout.close();

free(filebuffer);
}

int match(TOKEN_TYPE tokentype)
{
if(Token.Token_Type==tokentype) {Token=Get_Token(); return 1;}
else 
{
if (Token.Token_Type==ENDFILE)
{cout<<"Unexpected End of file"<<endl;
exit(0);
}
switch(tokentype)
{
        case ID :cout<<"Error:Identifier expected at:"<<Line_Num<<endl ; Token=Get_Token();break;
        case INT_CONST :cout<<"Error:Integer Constant expected  at:"<<Line_Num<<endl;Token=Get_Token();return 0  ;
        case FLOAT_CONST:cout<<"Error:Float Constant expected at:"<<Line_Num<<endl;Token=Get_Token();return 0;
        case STRING_CONST:cout<<"Error:String Constant expected at:"<<Line_Num<<endl;Token=Get_Token();return 0;
        case LEFT_C_B:cout<<"Error:Left Curl Bracket expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case RIGHT_C_B:cout<<"Error:Right Curl Bracket expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case SLASH:cout<<"Error:Slash  expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case QUOTE:cout<<"Error:Quote expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case COMMA:cout<<"Error:Comma expected at:"<<Line_Num<<endl;break;
        case STAR:cout<<"Error:Star  expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case PLUS:cout<<"Error:Plus  expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case MINUS:cout<<"Error:Minus expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case ENDFILE:cout<<"Error:EOF expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case EQU:cout<<"Error:Equal   expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case LESSEQU:cout<<"Error:Less or Equal  expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case LESS:cout<<"Error:Less   expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case GREATEQU:cout<<"Error:Greater or Equal   expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case GREAT:cout<<"Error:Greater expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case NON_EQU:cout<<"Error:Not Equal expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case ASSIGN:cout<<"Error:Assign expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case SEMICOLON:cout<<"Error:Semi Colon expected at:"<<Line_Num<<endl;break;
        case DOT:cout<<"Error:Dot expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case LEFT_R_B:cout<<"Error:Left Round Bracket expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case LEFT_RECT_B:cout<<"Error:Left Rectangle Bracket expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case BEGIN:cout<<"Error:Begin expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case END:cout<<"Error:End expected at:"<<Line_Num<<endl;break;
        case WHILE:cout<<"Error:While expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case DO:cout<<"Error:Do expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case REPEAT:cout<<"Error:Repeat  expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case UNTIL:cout<<"Error:Until expected at:"<<Line_Num<<endl;Token=Get_Token();break;
        case IF:cout<<"Error:If expected at:"<<Line_Num<<endl;Token=Get_Token();break;
	case RIGHT_R_B:cout<<"Error:Right Round Bracket expected at:"<<Line_Num<<endl;break;
	case THEN:cout<<"Error:Then Expected at:"<<Line_Num<<endl;break;
	case BOUND:cout<<"Error:BOUND Expected at:"<<Line_Num<<endl;break;
}//switch
while(Token.Token_Type!=SEMICOLON)
{
if(Token.Token_Type==ENDFILE)
exit(0);
Token=Get_Token();
}
return 0;
}
}//match

void program()
{
program_header();
block(0,"main",0);
strout<<"\treturn\n";
match(DOT);
exit(0);
}

void program_header()
{
Symbol *sym;
while(!match(PROGRAM))
match(PROGRAM);
if(Token.Token_Type==ID){
sym=(Symbol *)malloc(sizeof(Symbol));
strcpy(sym->name,Token.token);
sym->type=3;
push(&s);
current_install(sym,&s);
}
match(ID);
match(SEMICOLON);
}

void block(int block_flag,char *blockname,int paracount)
{
int var_count=paracount;
declarations(&var_count);
if(block_flag==0)
{
strout<<"main\n";
strout<<"\tenter "<<0<<"\n";
}else
{
strout<<"$"<<blockname<<block_flag<<"\n";
}
strout<<"\talloc\t"<<var_count-paracount<<"\n";
compound_statement();
pop(&s);
}

void declaration(int *var_count)
{
Symbol *ss;
int tt;

if(Token.Token_Type==VAR)
{
match(VAR);
variable_declarations(var_count);
}
else if(Token.Token_Type==PROCEDURE)
{
procedure_declaration();
}else if(Token.Token_Type==TYPE)
{
match(TYPE);
ss=(Symbol *)malloc(sizeof(Symbol));
strcpy(ss->name,Token.token);
match(ID);
match(EQU);
tt=type_process();
ss->type=0;
ss->type_entry=tt;
current_install(ss,&s);
match(SEMICOLON);
}
else
cout<<"Error:Type definition error at:"<<Line_Num<<endl;
}


void record_definition(int t)
{
int tt,i;
char idlist[8][32];
typetab[t].Ub=0;
typetab[t].type=5;//specifies that it is a record
int count=identifier_list(idlist);
match(COLON);

tt=type_process();
if(tt>=2)
cout<<"Error:A record can only have simple type as base type at Line:"<<Line_Num<<endl;
for(i=0;i<count;i++)
{
strcpy(typetab[t].Field[typetab[t].Ub].FieldName,idlist[i]);
typetab[t].Field[typetab[t].Ub].basetype=tt;
typetab[t].Ub++;
}
while(Token.Token_Type==SEMICOLON)
{
match(SEMICOLON);
if(Token.Token_Type==END)
break;
count=identifier_list(idlist);
match(COLON);
tt=type_process();
if(tt>=2)
cout<<"Error:A record can only have simple type as base type at Line:"<<Line_Num<<endl;

for(i=0;i<count;i++)
{
strcpy(typetab[t].Field[typetab[t].Ub].FieldName,idlist[i]);
typetab[t].Field[typetab[t].Ub].basetype=tt;
typetab[t].Ub++;
}
}

if(Token.Token_Type==ID)
{
cout<<"Error:Semicolon needed at:"<< Line_Num<<endl;
record_definition(t);
}//if
}//record_definition


int type_process()
{
Symbol *sym;
int tt;
if(Token.Token_Type==ID)
{
sym=look_up(Token.token,&s);
if(sym==NULL){cout<<"Error:Type Undefined at Line:"<<Line_Num<<endl;tt=0;}
else if(sym->type!=0)
{
cout<<"Error:"<<sym->name<<" is not a type in this scope  at Line:"<<Line_Num<<endl;
tt=0;
}
else tt=sym->type_entry;
match(ID);
}
else if(Token.Token_Type==ARRAY)
{
tt=type_index;
type_index++;
array_definition(tt);
}
else if(Token.Token_Type==RECORD)
{
match(RECORD);
tt=type_index;
type_index++;
record_definition(tt);
match(END);
}
else
{cout<<"Error:Not a proper Type at:"<<Line_Num<<endl;
 Token=Get_Token();
}
return tt;
}

void array_definition(int t)
{
int tt;
match(ARRAY);
match(LEFT_RECT_B);
typetab[t].type=4;//specifies it is an array
if(atoi(Token.token)!=1) 
cout<<"Error:An array index must start with 1 at Line:"<<Line_Num<<endl;
typetab[t].Lb=1;//this is an sumption
match(INT_CONST);
match(BOUND);
typetab[t].Ub=atoi(Token.token);
match(INT_CONST);
match(RIGHT_RECT_B);
match(OF);
if(Token.Token_Type==ARRAY)
{
cout<<"Error:An array can not have array as the base type at:"<<Line_Num<<endl;
recovery(ARRAY_BASE);
}else
{
tt=type_process();
if(typetab[tt].type==4)
cout<<"Error:Array can not have array as base type at Line:"<<Line_Num<<endl;
typetab[t].basetype=tt;
}
}//array_definition



void declarations(int *var_count)
{
while(Token.Token_Type==VAR||Token.Token_Type==PROCEDURE||Token.Token_Type==TYPE)
declaration(var_count);
}


void variable_declarations(int *var_count)
{
variable_declaration(var_count);
while(Token.Token_Type==ID)
{
variable_declaration(var_count);
}//while
}//variable_declarations


void variable_declaration(int *var_count)
{
char idlist[8][32];
int i,tt,tl;//to specify the type of the var list
int count=identifier_list(idlist);
int length=1;//the length of a variable
Symbol *ss;

match(COLON);
tt=type_process();
if(tt>=2) 
  {
  tl=typetab[tt].basetype;
  if(tl>=2)
  length=typetab[tl].Ub;
  length=length*typetab[tt].Ub;
  }//if
for(i=0;i<count;i++)
{
ss=new Symbol;
strcpy(ss->name,idlist[i]);
ss->type=1;//it is a variable
ss->passingconvention=0;//for processing convinience
ss->type_entry=tt;
ss->offset=*var_count+5;
*var_count=*var_count+length;
current_install(ss,&s);
}//for

match(SEMICOLON);
}//variable_declaration



int  identifier_list(char idlist[8][32])
{
int count=0;
if(Token.Token_Type==ID)
{
strcpy(idlist[count],Token.token);
count++;
}
match(ID);

while(Token.Token_Type==COMMA)
{
	match(COMMA);
	if(Token.Token_Type==ID)
	{
	strcpy(idlist[count],Token.token);
	count++;
	}
	match(ID);
}
/*1if(Token.Token_Type==ID)
{
cout<<"Error:Comma needed at Line:"<<Line_Num<<endl;

identifier_list();
}*///just do not handle this at this time


return count;
}

int  factor(int *left)
{
Symbol *sym;
int ft=0;
int l;
switch(Token.Token_Type)
{
case ID:  
	if((sym=look_up(Token.token,&s))==NULL)
        {
        cout<<"Error:Id "<<Token.token<<" undefined at Line :"<<Line_Num<<endl;
	Token=Get_Token();
	break;
	}
	if(sym->passingconvention==0)
	{
	if(leveldiff==0)
  	{
	strout<<"\tpusha\t"<<sym->offset<<"\n";
	}
	else
	strout<<"\tpushga\t"<<leveldiff<<"\t,"<<sym->offset<<"\n";
	} else //passingconvention==1
	{
	if(leveldiff==0)
  	{
	strout<<"\tpushI\t"<<sym->offset<<"\n";
	}
	else
	strout<<"\tpushgI\t"<<leveldiff<<" ,"<<sym->offset<<"\n";
	}
	match(ID);*left=1;ft=fact_prm(sym);break;
case STRING_CONST:
	ft=3;strout<<"\tpushs\t'"<< \
        Token.token<<"'\n";
	match(STRING_CONST);*left=0;break;
case INT_CONST:
	strout<<"\tpushcI\t"<<atoi(Token.token)<<"\n";
	match(INT_CONST);ft=0;*left=0;break;
case FLOAT_CONST:
        strout<<"\tpushcR "<<atof(Token.token)<<"\n";
	match(FLOAT_CONST);ft=1;*left=0;break;
case LEFT_R_B:
	match(LEFT_R_B);ft=expression(&l);*left=0;match(RIGHT_R_B);break;
}
return ft;
}

int fact_prm(Symbol *symb)
{
Symbol *sm;
int ft,i,mm,st,l;
if((symb->type!=1)&&(symb->type!=4))
 cout<<"Error:A variable or para is expected here at Line:"<<Line_Num<<endl;
ft=symb->type_entry;
switch(Token.Token_Type)
{
case DOT:
	match(DOT);mm=0;
	if(symb->passingconvention==999)//this means it is an array of records
	{
	strout<<"\tpushcI\t"<<typetab[symb->type_entry].Ub<<"\n";
	strout<<"\tmulI\n";
	} 

	for(i=0;i<typetab[symb->type_entry].Ub;i++)
	{
	if(strcasecmp(Token.token,typetab[symb->type_entry].Field[i].FieldName)==0)
        {
	mm=1;
	ft=typetab[symb->type_entry].Field[i].basetype;
        if(ft>=2)
  	cout<<"A record's base type must be simple at Line:"<<Line_Num<<endl;
	match(ID);
	strout<<"\tpushcI\t"<<i<<"\n";
	strout<<"\taddI\n";
	if(symb->passingconvention==999)
	strout<<"\taddI\n";
	return ft;
	}
	}//for
	cout<<"Not a Valid Field or not a record at Line:"<<Line_Num<<endl;
	ft=0;
	match(ID);break;
case LEFT_RECT_B:
	match(LEFT_RECT_B);
	st=simple_expression(&l);
	if(l==1)
	strout<<"\tfetchI\n";
	strout<<"\tpushcI 1\n";
	strout<<"\tsubI\n";
	match(RIGHT_RECT_B);
        if(st!=0) cout<<"Error:An array index must be an integer at Line:"<<Line_Num<<endl; 
        if(Token.Token_Type==DOT) 
         {
	sm=new Symbol;
	if(typetab[symb->type_entry].type!=4)
	cout<<"Error:Not a valid array at Line:"<<Line_Num<<endl;
	sm->type_entry=typetab[symb->type_entry].basetype;
        sm->type=1;//this is for process convenience
	sm->passingconvention=999;
	ft=fact_prm(sm);
        free(sm);
	} else {ft=typetab[symb->type_entry].basetype;strout<<"\taddI\n";}
        break;


}

return ft;

}//fact_prm

int term(int *left)
{
int ft1,ft2,oper,l;
ft1=factor(left);

if(Token.Token_Type==STAR||Token.Token_Type==DIV||Token.Token_Type==SLASH)
{
if(ft1==0&&
*left==1)
strout<<"\tfetchI\n";
if(ft1==1&&*left==1)
strout<<"\tfetchR\n";
}
while(Token.Token_Type==STAR||Token.Token_Type==DIV||Token.Token_Type==SLASH)
{
*left=0;
switch(Token.Token_Type)
{
case STAR:match(STAR);oper=STAR;break;
case SLASH:match(SLASH);oper=SLASH;break;
case DIV:match(DIV);oper=DIV;break;
}//switch

ft2=factor(&l);
if(ft2==0&&l==1)
strout<<"\tfetchI\n";
if(ft2==1&&l==1)
strout<<"\tfetchR\n";

switch(oper)
{
case STAR:
if((ft1==0)&&(ft2==0))
  {
  ft1=0;
  strout<<"\tmulI\n";
  }  else if(((ft1==0)&&(ft2==1))||((ft1==1)&&(ft2==0))||((ft1==1)&&(ft2==1)))
          {
	  if(ft1==0)
	  strout<<"\tfltb\n";
	  if(ft2==0)
	  strout<<"\tflt\n";
	  strout<<"\tmulR\n";
          ft1=1;
	  }
          else{
          cout<<"Error:Expression(* can only have int or real as operand) at Line:"<<Line_Num<<endl;
              }
break;
case SLASH:
if((ft1==0)&&(ft2==0))
  {
 ft1=1;
 strout<<"\tflt\n\tfltb\n\tdivR\n";
 
}  else if(((ft1==0)&&(ft2==1))||((ft1==1)&&(ft2==0))||((ft1==1)&&(ft2==1)))
          {
	  if(ft1==0)
	  strout<<"\tfltb\n";
	  if(ft2==0)
	  strout<<"\tflt\n";
	  strout<<"\tdivR\n";
          ft1=1;
         }
          else
          cout<<"Error:Expression(/ can only have int or real as operand) at Line:"<<Line_Num<<endl;
break;
case DIV:
if((ft1==0)&&(ft2==0))
  {
  ft1=0;
  strout<<"\tdivI\n";
  }  else    {
          cout<<"Error:Expression(div can only have integer operand) at Line:"<<Line_Num<<endl;
              }
break;

}//switch
}//while
return ft1;
}//term

int  expression(int *left)
{
int st1,st2,l,oper;
st1=simple_expression(left);
if(Token.Token_Type>=EQU&&Token.Token_Type<=NON_EQU)
{
oper=Token.Token_Type;
if(st1==0&&*left==1)
strout<<"\tfetchI\n";
if(st1==1&&*left==1)
strout<<"\tfetchR\n";
*left=0;
Token=Get_Token();
st2=simple_expression(&l);
if(st2==0&&l==1)
strout<<"\tfetchI\n";
if(st2==1&&l==1)
strout<<"\tfetchR\n";

switch(oper)
{
case EQU:
if((st1==0)&&(st2==0))
  {
  st1=0;
  strout<<"\teqI\n";
  }  else if(((st1==0)&&(st2==1))||((st1==1)&&(st2==0))||((st1==1)&&(st2==1)))
          {
          if(st1==0)
          strout<<"\tfltb\n";
          if(st2==0)
          strout<<"\tflt\n";
          strout<<"\teqR\n";
          st1=1;
          }
          else{
          cout<<"Error:+ or - can only have integer or real as operand at Line:"
<<Line_Num<<endl;
              }
break;
case NON_EQU:
if((st1==0)&&(st2==0))
  {
  st1=0;
  strout<<"\tneI\n";
  }  else if(((st1==0)&&(st2==1))||((st1==1)&&(st2==0))||((st1==1)&&(st2==1)))
          {
          if(st1==0)
          strout<<"\tfltb\n";
          if(st2==0)
          strout<<"\tflt\n";
          strout<<"\tneR\n";
          st1=1;
          }
          else{
          cout<<"Error:+ or - can only have integer or real as operand at Line:"
<<Line_Num<<endl;
 
            }
break;
case LESS:
if((st1==0)&&(st2==0))
  {
  st1=0;
  strout<<"\tltI\n";
  }  else if(((st1==0)&&(st2==1))||((st1==1)&&(st2==0))||((st1==1)&&(st2==1)))
          {
          if(st1==0)
          strout<<"\tfltb\n";
          if(st2==0)
          strout<<"\tflt\n";
          strout<<"\tltR\n";
          st1=1;
          }
          else{
          cout<<"Error:+ or - can only have integer or real as operand at Line:"
<<Line_Num<<endl;
 
            }
break;
case LESSEQU:
if((st1==0)&&(st2==0))
  {
  st1=0;
  strout<<"\tleI\n";
  }  else if(((st1==0)&&(st2==1))||((st1==1)&&(st2==0))||((st1==1)&&(st2==1)))
          {
          if(st1==0)
          strout<<"\tfltb\n";
          if(st2==0)
          strout<<"\tflt\n";
          strout<<"\tleR\n";
          st1=1;
          }
          else{
          cout<<"Error:+ or - can only have integer or real as operand at Line:"
<<Line_Num<<endl;
            }

break;
case GREAT:
if((st1==0)&&(st2==0))
  {
  st1=0;
  strout<<"\tgtI\n";
  }  else if(((st1==0)&&(st2==1))||((st1==1)&&(st2==0))||((st1==1)&&(st2==1)))
          {
          if(st1==0)
          strout<<"\tfltb\n";
          if(st2==0)
          strout<<"\tflt\n";
          strout<<"\tgtR\n";
          st1=1;
          }
          else{
          cout<<"Error:+ or - can only have integer or real as operand at Line:"
<<Line_Num<<endl;
            }
break;
case GREATEQU:
if((st1==0)&&(st2==0))
  {
  st1=0;
  strout<<"\tgeI\n";
  }  else if(((st1==0)&&(st2==1))||((st1==1)&&(st2==0))||((st1==1)&&(st2==1)))
          {
          if(st1==0)
          strout<<"\tfltb\n";
          if(st2==0)
          strout<<"\tflt\n";
          strout<<"\tgeR\n";
          st1=1;
          }
          else{
          cout<<"Error:+ or - can only have integer or real as operand at Line:"
<<Line_Num<<endl;
            }
}//switch

if(st1<=1&&st2<=1)
return 2;
}//if
return st1;
}

int  simple_expression(int *left)
{
int tt1=-1,tt2,l,le=0,oper;
if(Token.Token_Type==PLUS||Token.Token_Type==MINUS)
{
le=1;
if(Token.Token_Type==MINUS) le=2;
Token=Get_Token();
}
if(Token.Token_Type!=ID&&Token.Token_Type!=LEFT_R_B \
&&Token.Token_Type!=STRING_CONST&&Token.Token_Type!=FLOAT_CONST \
&&Token.Token_Type!=INT_CONST&&Token.Token_Type!=LEFT_R_B)
{
if(Token.Token_Type==RIGHT_RECT_B) 
return tt1;
cout<<"Error:Not a valid simple expression at:"<<Line_Num<<endl;
Token=Get_Token();
}
tt1=term(left);
if(*left==1&&le!=0) 
	{*left=0;if(tt1==0)
	strout<<"\tfetchI\n"; 
	if(tt1==1)
	strout<<"\tfetchR\n";
	if(le==2&&tt1==0)
	strout<<"\tnegI\n";
	if(le==2&&tt1==1)
	strout<<"\tnegR\n";
	}//this means that it does not have left value
else

if(Token.Token_Type==PLUS||Token.Token_Type==MINUS)
{
if(*left==1) 
	{*left=0;if(tt1==0)
	strout<<"\tfetchI\n"; 
	if(tt1==1)
	strout<<"\tfetchR\n";
	if(le==2&&tt1==0)
	strout<<"\tnegI\n";
	if(le==2&&tt1==1)
	strout<<"\tnegR\n";
	}//this means that it does not have left value
}
while(Token.Token_Type==PLUS||Token.Token_Type==MINUS)
{
*left=0;
switch(Token.Token_Type)
{
case PLUS:match(PLUS);oper=PLUS;break;
case MINUS:match(MINUS);oper=MINUS;break;
}//switch
tt2=term(&l);
if(l==1&&tt2==0)
strout<<"\tfetchI\n";
if(l==1&tt2==1)
strout<<"\tfetchR\n";


switch(oper)
{
case PLUS:
if((tt1==0)&&(tt2==0))
  {
  tt1=0;
  strout<<"\taddI\n";
  }  else if(((tt1==0)&&(tt2==1))||((tt1==1)&&(tt2==0))||((tt1==1)&&(tt2==1)))
          {
	  if(tt1==0)
	  strout<<"\tfltb\n";
	  if(tt2==0)
	  strout<<"\tflt\n";
	  strout<<"\taddR\n";
          tt1=1;
          }
          else{
          cout<<"Error:+ or - can only have integer or real as operand at Line:"<<Line_Num<<endl;
              }
break;
case MINUS:
if((tt1==0)&&(tt2==0))
  {
  tt1=0;
  strout<<"\tsubI\n";
  }  else if(((tt1==0)&&(tt2==1))||((tt1==1)&&(tt2==0))||((tt1==1)&&(tt2==1)))
          {
          if(tt1==0)
          strout<<"\tfltb\n";
          if(tt2==0)
          strout<<"\tflt\n";
          strout<<"\tsubR\n";
          tt1=1;
          }
          else{
          cout<<"Error:+ or - can only have integer or real as operand at Line:"
<<Line_Num<<endl;
              }
}//switch2


}//while
return tt1;
}//siple_expression



int  expression_list(Symbol *sym)
{
int count=0;
int left=0;
parapass[count]=expression(&left);
if(left==1&&sym->paralist[count].passingconvention==0)
{
if(sym->paralist[count].type==1&&parapass[count]==0)
{
strout<<"\tfetchI\n";
strout<<"\tflt\n";
}else 
if(parapass[count]==0)
strout<<"\tfetchI\n";
else if(parapass[count]==1)
strout<<"\tfetchR\n";
}//if
lvalue[count]=left;
count++;
while(Token.Token_Type==COMMA)
{
match(COMMA);
parapass[count]=expression(&left);

if(left==1&&sym->paralist[count].passingconvention==0)
{
if(sym->paralist[count].type==1&&parapass[count]==0)
{
strout<<"\tfetchI\n";
strout<<"\tflt\n";
}else 
if(parapass[count]==0&&sym->paralist[count].type==0)
strout<<"\tfetchI\n";
else if(sym->paralist[count].type==1)
strout<<"\tfetchR\n";
}//if
lvalue[count]=left;
count++;
}//while
return count;
}//expression_list


void statement()
{
Symbol *sym;
int label,elselabel,endlabel;//for label use
int exprtype,et,ft,l2,l1;
int left;
int difference;
if(Token.Token_Type!=BEGIN&&Token.Token_Type!=END&&Token.Token_Type!=REPEAT \
   &&Token.Token_Type!=IF&&Token.Token_Type!=WHILE&&Token.Token_Type!=ID \
   &&Token.Token_Type!=SEMICOLON \
   &&Token.Token_Type!=UNTIL)
{
cout<<"Error:Unexpected Token at :"<<Line_Num<<endl;
if(Token.Token_Type==ENDFILE)
{
cout<<"Unexpected end of file"<<endl;
exit(0);
}else
Token=Get_Token();
}

switch(Token.Token_Type)
{
case BEGIN:compound_statement();break;

case IF:match(IF);exprtype=expression(&left);
elselabel=get_label();
endlabel=get_label();
strout<<"\tjumpz $"<<elselabel<<"\n";

if(exprtype!=2){cout<<"Error:If must be followed by a bool expr at Line:"<<Line_Num<<endl;}
match(THEN);statement();
strout<<"\tjump $"<<endlabel<<"\n";
strout<<"$"<<elselabel<<"\n";
else_suffix(endlabel);break;

case REPEAT:match(REPEAT);
label=get_label();
strout<<"$"<<label<<"\n";

statement_list();match(UNTIL);exprtype=expression(&left);
if(exprtype!=2){cout<<"Error:Until must be followed by a bool expr at Line:"<<Line_Num<<endl;}
strout<<"\tjumpz $"<<label<<"\n";
break;

case WHILE:match(WHILE);
label=get_label();
endlabel=get_label();
strout<<"$"<<label<<"\n";


exprtype=expression(&left);

strout<<"\tjumpz $"<<endlabel<<"\n";
if(exprtype!=2){cout<<"Error:While must be followed by a bool expr at Line:"<<Line_Num<<endl;}
match(DO);statement();
strout<<"\tjump $"<<label<<"\n";
strout<<"$"<<endlabel<<"\n";
break;

case ID:sym=look_up(Token.token,&s);
	sym->leveldiff=leveldiff;
        if(sym->type==1||sym->type==4)//it is a var or parameter
	{
	ft=factor(&l2);
	if(l2==0){cout<<"Error:Do not have l-value at Line"<<Line_Num<<endl;}
	match(ASSIGN);
	et=expression(&l1);
	if(l1==1&&et==0)
	strout<<"\tfetchI\n";
	if(l1==1&&et==1)
	strout<<"\tfetchR\n";
	if(et==0&&ft==1)
	strout<<"\tflt\n";
	if(ft==0&&et==1) cout<<"Error:Not compatible Assignment at Line:"<<Line_Num<<endl;
	if(ft==0)
	strout<<"\tpopiI\n";
	else if(ft==1)
	strout<<"\tpopiR\n";
	else cout<<"Error:Assignment is not correct at Line:"<<Line_Num<<endl;
	break;
	}
	if(sym->type==2&&sym->type_entry==0&&sym->leveldiff==s.current_index)
	{
	strout<<"\tenter "<<0<<"\n";
	strout<<"\tcall $"<<"WriteLn"<<" ,"<<0<<"\n";
	match(ID);
	break;
	}//if

	if(sym->type==2&&sym->type_entry==0&&sym->leveldiff!=s.current_index)
	{
	strout<<"\tenter "<<sym->leveldiff<<"\n";
	strout<<"\tcall $"<<sym->name<<sym->entry_point<<" ,"<<0<<"\n";
	match(ID);
	break;
	}//if

	if(sym->type==2&&sym->type_entry!=0&&sym->leveldiff==s.current_index)
	{
	strout<<"\tenter "<<0<<"\n";
	}

	if(sym->type==2&&sym->type_entry!=0&&sym->leveldiff!=s.current_index)
	{
	strout<<"\tenter "<<sym->leveldiff<<"\n";
	}

        if(sym==NULL)
        {cout<<"Error:Id " <<Token.token<<" Not Defined at Line:"<<Line_Num<<endl;
        while(Token.Token_Type!=END&&Token.Token_Type!=SEMICOLON)
	Token=Get_Token();break;} 
	match(ID);id_suffix(sym);break;

case SEMICOLON:break;
}//switch
}//statement

void id_suffix(Symbol *sym)
{
Symbol *sm;
int rt=-1,i, count=0,tt,st;
int left;
switch(Token.Token_Type)
{
/*******************procedure with para**********************/
case LEFT_R_B:match(LEFT_R_B);
if(sym->type_entry==0)
{cout<<"Error:Can not have Brackets here  as para # is zero at Line:"<<Line_Num<<endl;
while(Token.Token_Type!=SEMICOLON&&Token.Token_Type!=END)
Token=Get_Token();
return;
}
count=expression_list(sym);
if(sym->type!=2)
cout<<"Not a valid procedure at Line:"<<Line_Num<<sym->name<<endl;
else if(count!=sym->type_entry)
     cout<<"Do not have the same # of Para at Line:"<<Line_Num<<endl;
else for(i=0;i<count;i++)
     {
     if(sym->paralist[i].type==parapass[i] )
	{

	}

     else if(sym->paralist[i].type==99&&(parapass[i]==0||parapass[i]==1 \
              ||parapass[i]==3)) ; else if
      (sym->paralist[i].type==98&&(parapass[i]==0||parapass[i]==1))
               ; else 
     cout<<"Error:The " <<i+1 <<" Para type is not valid at Line:"<<Line_Num<<endl;

     if(lvalue[i]==0&&sym->paralist[i].passingconvention==1)
     cout<<"Error:Can not pass by reference as no left value at Line:"<<Line_Num<<endl; 
   }

if(sym->leveldiff==s.current_index)//predefined procedure
{
if(strcmp(sym->name,"write")==0)
{
if(parapass[0]==0)
strout<<"\tcall\t$WriteInt ,"<<1<<"\n";
if(parapass[0]==1)
strout<<"\tcall\t$WriteReal ,"<<1<<"\n";
if(parapass[0]==3)
strout<<"\tcall\t$WriteStri ,"<<1<<"\n";
}

if(strcmp(sym->name,"readln")==0)
{
if(parapass[0]==0)
strout<<"\tcall\t$ReadInt ,"<<1<<"\n";
if(parapass[0]==1)
strout<<"\tcall\t$ReadReal ,"<<1<<"\n";
}

}


if(sym->leveldiff!=s.current_index)//predefined procedure
{
strout<<"\tcall\t$"<<sym->name<<sym->entry_point<<" ,"<<count<<"\n";
}
match(RIGHT_R_B);
break;
default:if(sym->type!=2) 
cout<<"This must be a procedure "<<Token.token<<" at Line:"<<Line_Num<<endl;
if(sym->type==2&&sym->type_entry!=0)
cout<<"Error:Illegal procedure call at Line:"<<Line_Num<<endl;
}//switch

}//id_suffix

void else_suffix(int endlabel)
{
if(Token.Token_Type==ELSE)
{
match(ELSE);
statement();
}
strout<<"$"<<endlabel<<"\n";
}//else_suffix

void statement_list()
{
statement();
if(Token.Token_Type!=SEMICOLON&&Token.Token_Type!=UNTIL&&Token.Token_Type!=END)
{
match(SEMICOLON);
return;
}
while(Token.Token_Type==SEMICOLON)
{
match(SEMICOLON);
statement();
}//while
if(Token.Token_Type!=END&&Token.Token_Type!=UNTIL)
{
cout<<"Error:Semicolon expecetd at "<<Line_Num<<endl;
statement_list();
}
}//statement_list

void compound_statement()
{
match(BEGIN);
if(Token.Token_Type==END)
{
match(END);
return;
}
statement_list();
match(END);
}//compound_statement

void parameter_group()
{
int count,i,tt;
int passing=0;
char idlist[8][32];
if(Token.Token_Type==VAR)
{
match(VAR);
passing=1;
count=identifier_list(idlist);
match(COLON);
tt=type_process();
}else
{
count=identifier_list(idlist);
match(COLON);
tt=type_process();
}//
for(i=0;i<count;i++)
{
paralisttype[paraindex].passingconvention=passing;
paralisttype[paraindex].type=tt;
strcpy(paralist[paraindex],idlist[i]);
paraindex++;
}

}//parameter_group

void parameter_list()
{
parameter_group();
while(Token.Token_Type==SEMICOLON)
{
match(SEMICOLON);
parameter_group();
}//while
}//parameter_list

char * procedure_header(int *procseq,int *paracount)
{
int i;
Symbol *sym=new Symbol;
char *proc;
match(PROCEDURE);
strcpy(sym->name,Token.token);
proc=sym->name;
sym->type=2;//it is procedure
match(ID);
paraindex=0;
if(Token.Token_Type==LEFT_R_B)
{
match(LEFT_R_B);
parameter_list();
match(RIGHT_R_B);
}
for(i=0;i<paraindex;i++)
  {
  if(paralisttype[i].type>=2&&paralisttype[i].passingconvention!=1)
  cout<<"Error:A Reord or Array must be passed by refernece at Line:"<<Line_Num<<endl;
  sym->paralist[i].passingconvention=paralisttype[i].passingconvention;
  sym->paralist[i].type=paralisttype[i].type;
  }
sym->type_entry=paraindex; 
sym->entry_point=*procseq=get_label();
current_install(sym, &s);
push(&s);
for(i=0;i<paraindex;i++)
{
sym=new Symbol;
strcpy(sym->name,paralist[i]);
sym->type=4;//it is a parameter
sym->offset=5+i;
sym->type_entry=paralisttype[i].type;
sym->passingconvention=paralisttype[i].passingconvention;
current_install(sym,&s);
}
*paracount=paraindex;
match(SEMICOLON);
return proc;
}

void procedure_declaration()
{
int procseq;
char *proc;
int paracount;
proc=procedure_header(&procseq,&paracount);
block(procseq,proc,paracount);
strout<<"\treturn\n";
match(SEMICOLON);
}//procedure_declaration

void recovery(int errorcode)
{
switch(errorcode)
{
case ARRAY_BASE:while(Token.Token_Type!=SEMICOLON&&Token.Token_Type!=END)
                Token=Get_Token();
                break;
default:while(Token.Token_Type!=SEMICOLON&&Token.Token_Type!=END)
        Token=Get_Token();
        break;
}//switch
}//recovery
