//Main of Scanner
//Author:Guangming Xing
//Date:  Apr 5 1998
//undefine the EXTERN so that we can get
//the real variable here
#define EXTERN 


#include "symbtab.h"
#include "scanner.h"
#include "global.h"
TOKEN Token;
void Transition_Pro(void);

char Key_Word[KEYNUM][16]={"begin","end","while","do","repeat","until","if","then","else","program","var","procedure","type","record","div","array","of"};


TOKEN Get_Token(void)
{
//Initialization
Token.Token_Type=UNUSED;
for(int i=0;i<64;i++)
Token.token[i]='\0';
Start=IDLE;
State=IDLE;
while(c!=EOF)
{

 switch(State)
 {
	case IDLE://check for white space and Tab
	if(isspace(c))
	{
	if(c==EOF)
	{
	Get_Lex(ENDFILE);
	break;
	}
	Token_Begin++;
	if(c=='\n')
	Line_Num++;
	State=WHITESPACE;
	Next_Char();
	break;
	}
	else
	{
	Transition_Pro();//must for non-space process
	break;
	}

	case WHITESPACE://Proceed with white Space
	if(isspace(c))
	{
	Token_Begin++;
	if(c=='\n') Line_Num++;
	State=WHITESPACE;
	Next_Char();
	break;
	}
	else//go to state for Transition Process
	{
	State=IDLE;
	break;
	}

	case COMMENT_CB:
	//check for comment with {
	Comment_CB_Pro();
	State=IDLE;
	Token_Begin=Proceed-1;
	break;

	case COMMENT_RB:
	//check for comment with (*
	Comment_RB_Pro();
	State=IDLE;
	Token_Begin=Proceed-1;
	break;

	case NUMBERPRO:
	//process the number
	Number_Pro();
	State=IDLE;
	break;
	
	case IDENTIFIERPRO:
	Identifier_Pro();
	State=IDLE;
	break;

	case STRPRO:
	String_Pro();
	State=IDLE;
	break;


}//end of switch


if(Token.Token_Type!=UNUSED)
break;
}//end of while
if(c==EOF)
Token.Token_Type=ENDFILE;
return Token;
}//end of Get_Token

void Get_Lex(TOKEN_TYPE t)
{
int i;//just temporary
for(i=0;i<64;i++)
Token.token[i]='\0';
Token.Token_Type=t;
for(i=Token_Begin;i<Proceed-1;i++)
Token.token[i-Token_Begin]=filebuffer[i];
Token.token[i-Token_Begin]='\0';
Token_Begin=Proceed-1;
}

int Is_Key(char *str)
{
int i;
for(i=0;i<KEYNUM;i++)
{
  if(strcasecmp(str,Key_Word[i])==0)
  break;
}
if(i==KEYNUM)
return(-1);
else
return (24+i);
}//End of Is_key

int Is_Div(char *str)
{
if (strcasecmp(str,"div"))
return DIV;
else return -1;
}


void Next_Char()
{
c=filebuffer[Proceed];
forward=filebuffer[Proceed+1];
Proceed++;
}
//the follow is the transform function

void Transition_Pro()
{
if(c=='{')    //comment { begins
{
Start=State=COMMENT_CB;
Next_Char();
return;
}
if((c=='(')&&(forward=='*'))
{
Start=State=COMMENT_RB;
Next_Char();
Next_Char();
return;
}else if(c=='(')
{
State=IDLE;
Next_Char();
Get_Lex(LEFT_R_B);
return;
}
if(c==')')
{
State=IDLE;
Next_Char();
Get_Lex(RIGHT_R_B);
return;
}

if(c=='[')
{
State=IDLE;
Next_Char();
Get_Lex(LEFT_RECT_B);
return;
}
if(c==']')
{
State=IDLE;
Next_Char();
Get_Lex(RIGHT_RECT_B);
return;
}

if(c=='\'')
{
Start=State=STRPRO;
//Let the String constant skip the '
Token_Begin=Proceed;
Next_Char();
return;
}

if(c=='+')
{
State=IDLE;
Next_Char();
Get_Lex(PLUS);
return;
}
if(c=='-')
{
State=IDLE;
Next_Char();
Get_Lex(MINUS);
return;
}
if(c==',')
{
State=IDLE;
Next_Char();
Get_Lex(COMMA);
return;
}
if((c=='.')&&(forward=='.'))
{
State=IDLE;
Next_Char();
Next_Char();
Get_Lex(BOUND);
return;
}
if(c=='.')
{
State=IDLE;
Next_Char();
Get_Lex(DOT);
return;
}

if(c=='*')
{
State=IDLE;

Next_Char();
Get_Lex(STAR);
return;
}
if(c=='/')
{
State=IDLE;
Next_Char();
Get_Lex(SLASH);
return;
}
if(c=='>')
{
	if(forward=='=')
	{
	State=IDLE;
	Next_Char();
	Next_Char();
	Get_Lex(GREATEQU);
	return;
	}
	else
	{
	State=IDLE;
	Next_Char();
	Get_Lex(GREAT);
	return;
	}
}
if(c=='<')
{
        if(forward=='=')
        {
        State=IDLE;
        Next_Char();
        Next_Char();
        Get_Lex(LESSEQU);
        return;
        }
        else if(forward=='>')
	{State=IDLE;
	Next_Char();
	Next_Char();
	Get_Lex(NON_EQU);
	return;
	}else
        {
        State=IDLE;
        Next_Char();
        Get_Lex(LESS);
        return;
        }
}
if(c=='=')
{
State=IDLE;
Next_Char();
Get_Lex(EQU);
return;
}
if((c==':')&&(forward=='='))
{
State=IDLE;
Next_Char();
Next_Char();
Get_Lex(ASSIGN);
return;
}
if(c==':')
{
State=IDLE;
Next_Char();
Get_Lex(COLON);
return;
}
if(c==';')
{
State=IDLE;
Next_Char();
Get_Lex(SEMICOLON);
return;
}
if(c=='\0')
{
Get_Lex(ENDFILE);
return;
}
if(isalpha(c))
{
State=IDENTIFIERPRO;
Next_Char();
return;
}
if(isdigit(c))
{
State=NUMBERPRO;
Next_Char();
return;
}
Err_Pro();
Next_Char();
Token_Begin++;
}


//This is for ID and Keyword processing

void Identifier_Pro()
{
int i;
while(isalnum(c))
Next_Char();
Get_Lex(ID);
if((i=Is_Key(Token.token))>0)
(int)(Token.Token_Type)=i;
State=IDLE;
//else Token.Token_Type=ID;
}

//The following is the processing for Number

void Number_Pro()
{
while(isdigit(c))
Next_Char();
//if a number is followed by two dots
if((c=='.')&&(forward=='.'))
{
State=IDLE;
Get_Lex(INT_CONST);
return;
}
if((c=='.')&&(isdigit(forward)))
{
State=REALNUMPRO;
Next_Char();
Real_Number_Pro();
}//if
else if(c!='.')
{
if(isalpha(c))
cout<<"Error:A Number must be seperated from a IDENT at :"<<Line_Num<<endl;
State=IDLE;
Get_Lex(INT_CONST);
} else
{
Get_Lex(INT_CONST);
Next_Char();
Token_Begin=Proceed-1;
Err_Pro();
}

}

//The following is for real Number Processing

void  Real_Number_Pro()
{

while(isdigit(c))
Next_Char();
if(c=='e'||c=='E')
{
State=EXPONENTPRO;
Next_Char();
Exponent_Pro();
}
else
if(isalpha(c))
{
//Err_Pro();
cout<<"Error:A Real Number must be seperated from a IDENT"<<endl;

Get_Lex(FLOAT_CONST);
Token_Begin=Proceed;
State=IDLE;
}else
Get_Lex(FLOAT_CONST);
State=IDLE;
}

//The following is for exponent processing

void Exponent_Pro()
{
if((c=='+'||c=='-')&&isdigit(forward))
{
Next_Char();
while(isdigit(c))
Next_Char();
}
else if(isdigit(c))
{
while(isdigit(c))
Next_Char();
}else if((c=='+'||c=='-')&&!isdigit(forward))
{
cout<<"Error:Not a valid Real Number at:"<<Line_Num<<endl;
State=IDLE;
Proceed--;
Get_Lex(FLOAT_CONST);
Proceed++;
return;
}else if (!isdigit(c))
{
cout<<"Error:Not a Valid Real Number at:" <<Line_Num<<endl;
State=IDLE;
Proceed--;
Get_Lex(FLOAT_CONST);
Proceed++;
return;
}
if(isalpha(c))
{
//Err_Pro();
cout<<"Error:A Real Number must be seperated from a IDENT"<<endl;
Get_Lex(FLOAT_CONST);
Token_Begin=Proceed-1;
State=IDLE;
}else
Get_Lex(FLOAT_CONST);
State=IDLE;

}//end of Exponent_Pro


//the Following is the String Processing

void String_Pro()
{
ll:while(c!='\''&&c!='\n'&&c!=EOF)
Next_Char();
if((c=='\'')&&(forward=='\''))
{
Next_Char();
Next_Char();
goto ll;
}

if(c=='\'')
{
Get_Lex(STRING_CONST);
Next_Char();
State=IDLE;
Token_Begin=Proceed-1;
}
else {
Err_Pro();//can not find the match of '
Get_Lex(STRING_CONST);
}

}//end of String Pro

void Comment_CB_Pro()
{
while((c!='}')&&(c!='\0'))
{
if(c=='\n')
Line_Num++;
Next_Char();
}
if(c=='}')
{
Next_Char();
}else
Err_Pro();
}

void Comment_RB_Pro()
{
while(((c!='*')||(forward!=')'))&&(c!='\0'))
{
if(c=='\n')
Line_Num++;
Next_Char();
}

if((c=='*')&&(forward==')'))
{
Next_Char();
Next_Char();
}
else
Err_Pro();

}

void Err_Pro()
{
if(State==STRPRO)
cout<<"Error:The string does not terminate correctly at:"<<Line_Num<<endl;
if(State==COMMENT_CB)
cout<<"Error:Curly Bracket Comment does not match at:"<<Line_Num<<endl;
if(State==COMMENT_RB)
cout<<"Error:Round Bracket Comment does not match at:"<<Line_Num<<endl;
if(State==NUMBERPRO)
cout<<"Error:Not a valid Real Number,let it be Integer at:"<<Line_Num<<endl;
if(State==IDLE)
cout<<"Error:Not a valid Pascal Program symbol,"<<c<<" at:"<<Line_Num<<endl;
State=IDLE;

}


