/*                      QBCC Project

This source file is licensed under the GNU Public Licence which should be 
included with the distribution of this source.

*/
// Scanner

#include "qbcc.h"
#include "scanner.h"
#include "info.h"
#include "error.h"

int FileStart = TRUE;
int LineNumber = 1;

///////////////////
// Go to the next line
void NextLine(int linetype)
{		
	while(curToken->type != linetype && curToken->type != TK_NEWLINE)
		GetToken();
}

///////////////////
// Restart the file scanner
void RestartScanner(void)
{
	fseek(infile,0,SEEK_SET);
	yyrestart(infile);
	FileStart = TRUE;
	LineNumber = 1;
	
	curToken->type = -1;	
	strcpy(curToken->text,"");	
	curToken->VarType = DefStruct->DefaultType;
	LookToken->type = -1;
	strcpy(LookToken->text,"");
	LookToken->VarType = DefStruct->DefaultType;
}

///////////////////
// Get a token
void GetToken(void)
{
	char buf[4096];
	int temptype = DefStruct->DefaultType;
	unsigned int n,i;
	func_t *poldfunc = curFUNC;

	if(FileStart)
	{		
		// Current Token		
		curToken->type = yylex();
		strcpy(curToken->text,yytext);
		curToken->VarType = VarType;
		curToken->flags = 0;

		// Look Ahead
		LookToken->type = yylex();
		strcpy(LookToken->text,yytext);
		LookToken->VarType = VarType;
		LookToken->flags = 0;
	}
	else
	{
		memcpy(curToken,LookToken,sizeof(token_t));

		// Look Ahead
		LookToken->type = yylex();
		strcpy(LookToken->text,yytext);
		LookToken->VarType = VarType;
		LookToken->flags = 0;
	}

	if(curToken->type == TK_NEWLINE || curToken->type == TK_COMMENT)
		LineNumber++;

	// Do some checking
	if(curToken->type == TK_UNKNOWN)
	{		
		poldfunc = curFUNC;
		if(FindFunction(curToken->text,TRUE) == TRUE)
		{
			curToken->VarType = curFUNC->ret;
			curToken->type = TK_FUNCTION;
			curToken->flags |= TKF_VARPTR;
		}
		else if(IsVariable(curToken->text,&temptype) == TRUE)
			curToken->type = TK_VARIABLE;
		else if(IsArguement(curToken->text,&temptype) == TRUE)
			curToken->type = TK_VARIABLE;
		curFUNC = poldfunc;
	}	
	if(LookToken->type == TK_UNKNOWN)
	{
		poldfunc = curFUNC;
		if(FindFunction(LookToken->text,TRUE) == TRUE)
		{			
			LookToken->type = TK_FUNCTION;
			LookToken->flags |= TKF_VARPTR;
			LookToken->VarType = curFUNC->ret;			
		}
		else if(IsVariable(LookToken->text,&temptype) == TRUE)
			LookToken->type = TK_VARIABLE;
		else if(IsArguement(LookToken->text,&temptype) == TRUE)
			LookToken->type = TK_VARIABLE;
		curFUNC = poldfunc;
	}

	// This is a bit fucking silly
	// And NO, your not seeing double! it's the code thats twice as....messy

	// Set Flags
	if(curToken->type == TK_VARIABLE)	
		if(IsArguement(curToken->text,&temptype))
			curToken->flags |= TKF_ARGUEMENT;
	if(curToken->VarType == VAR_FILE)
		curToken->flags |= TKF_FILE;


	if(LookToken->type == TK_VARIABLE)
		if(IsArguement(LookToken->text,&temptype))
			LookToken->flags |= TKF_ARGUEMENT;
	if(LookToken->VarType == VAR_FILE)
		LookToken->flags |= TKF_FILE;


	if(curToken->type == TK_UNRECOGNIZE)
	{
		// Uh oh
		sprintf(buf,"Unrecognized character '%s'",curToken->text);
		SysError(__LINE__,"GetToken",buf);
	}

	// Set the right VarType's	
	if(curToken->type == TK_VARIABLE)
	{
		if(IsArguement(curToken->text,&temptype))		
			curToken->VarType = temptype;
		else
		{
			if(IsVariable(curToken->text,&temptype))
				curToken->VarType = temptype;
		}
	}
	if(LookToken->type == TK_VARIABLE)
	{		
		if(IsArguement(LookToken->text,&temptype))
			LookToken->VarType = temptype;
		else
		{
			if(IsVariable(LookToken->text,&temptype))
				LookToken->VarType = temptype;
		}
	}

	// Fix String Constanst's	
	if(curToken->type == TK_STRINGCONSTANT && FileStart)
	{
		strcpy(buf,"");
		for(n=0,i=0;n<=strlen(curToken->text);n++)
		{
			if(curToken->text[n] == '\\')			
			{
				buf[i++] = '\\';
				buf[i++] = '\\';
			}
			else			
				buf[i++] = curToken->text[n];
		}		
		strcpy(curToken->text,buf);
	}

	if(LookToken->type == TK_STRINGCONSTANT)
	{
		strcpy(buf,"");
		for(n=0,i=0;n<=strlen(LookToken->text);n++)
		{
			if(LookToken->text[n] == '\\')			
			{
				buf[i++] = '\\';
				buf[i++] = '\\';
			}
			else			
				buf[i++] = LookToken->text[n];			
		}		
		strcpy(LookToken->text,buf);
	}

	FileStart = FALSE;
}


///////////////////
// Checks if it's a variable
int IsVariable(char *name,int *VarType)
{	
	func_t *tempfunc;
	var_t *tempvar;

	// First check global function
	tempfunc = curFUNC;
	FindFunction("__BC_GLOBAL__",TRUE);
	tempvar = curFUNC->vars;
	while(tempvar->prev != NULL)
		tempvar = tempvar->prev;
	while(tempvar != NULL)
	{
		if(strcmp(tempvar->name,name) == 0)
		{
			curFUNC = tempfunc;
			*VarType = tempvar->type;
			return TRUE;
		}
		tempvar = tempvar->next;
	}
	
	curFUNC = tempfunc;
	// Check function's variable list
	tempvar = curFUNC->vars;
	while(tempvar->prev != NULL)
		tempvar = tempvar->prev;
	while(tempvar != NULL)
	{
		if(stricmp(tempvar->name,name) == 0)		
		{
			*VarType = tempvar->type;
			return TRUE;
		}
		tempvar = tempvar->next;
	}


	// I took 2 fucking stressful hours to debug the code, only to find this part section
	// shouldn't be here
	// It's staying commented out until it dies!!!!!!!

	/*// Check function's arguement list
	tempvar = curFUNC->args;
	while(tempvar->prev != NULL)
		tempvar = tempvar->prev;
	while(tempvar != NULL)
	{
		if(stricmp(tempvar->name,name) == 0)
		{
			*VarType = tempvar->type;
			return TRUE;
		}
		tempvar = tempvar->next;
	}*/

	return FALSE;
}

///////////////////
// Returns if the variable is an argument
int IsArguement(char *name,int *VarType)
{
	var_t *tempvar = NULL;
		
	tempvar = curFUNC->args;
	while(tempvar->prev != NULL)
		tempvar = tempvar->prev;
	while(tempvar != NULL)
	{
		if(stricmp(tempvar->name,name) == 0)
		{
			*VarType = tempvar->type;
			return TRUE;
		}
		tempvar = tempvar->next;
	}

	return FALSE;
}

///////////////////
// Returns if the variable in a member of the current TYPE
int IsMember(char *name, int *VarType)
{
	var_t *tempvar = NULL;
	
	if(curTYPE)
		tempvar = curTYPE->vars;

	if(tempvar == NULL)
		return FALSE;

	while(tempvar->prev != NULL)
		tempvar = tempvar->prev;
	while(tempvar != NULL)
	{
		if(stricmp(tempvar->name,name) == 0)
		{
			*VarType = tempvar->type;
			return TRUE;
		}
		tempvar = tempvar->next;
	}

	return FALSE;
}

///////////////////
// Match a string against the token
void Match(char *string)
{
	char buf[81];
	GetToken();
	if(strcmp(curToken->text,string) != 0)
	{

		if(stricmp(string,"\n") == 0)
			sprintf(buf,"Expected 'newline', instead got '%s'\n",curToken->text);
		else
			sprintf(buf,"Expected '%s', instead got '%s'\n",string,curToken->text);
		BASError(LineNumber,buf);
	}
}
