/*                      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"
#include "keyword.h"
#include "variable.h"
#include "translate.h"
#include "scanner.h"

///////////////////
// Translate KEYWORDS
int TranslateKEYWORD(char *keyword)
{	
	// Returns whether or not to break the 'Code Block'	
	char retstr[4096];
	char buf[128];
	int IF_OneLine = FALSE;

	strcpy(retstr,"");
	PrintDepth(retstr);
	if(strcmp(keyword,"DECLARE") == 0)						// DECLARE keyword
	{
		Keyword_DECLARE(retstr);
		fprintf(outfile,"%s",retstr);
		return FALSE;
	}

	if(strcmp(keyword,"TYPE") == 0)							// TYPE keyword
	{
		Keyword_TYPE(retstr);
		fprintf(outfile,"%s",retstr);
		return FALSE;
	}

	if(strcmp(keyword,"DIM") == 0)							// DIM keyword
	{
		Keyword_DIM(retstr);
		fprintf(outfile,"%s",retstr);
		return FALSE;
	}

	if(strcmp(keyword,"REDIM") == 0)						// REDIM keyword
	{
		// Same as DIM coz it's not supported
		Keyword_DIM(retstr);
		fprintf(outfile,"%s",retstr);
		return FALSE;
	}

	if(strcmp(keyword,"SUB") == 0)							// SUB keyword
	{
		Keyword_SUB(retstr,FN_SUB);
		fprintf(outfile,"%s",retstr);
		// Run another code block
		Block(TRUE,FALSE);
		return FALSE;
	}

	if(strcmp(keyword,"FUNCTION") == 0)						// FUNCTION keyword
	{
		Keyword_SUB(retstr,FN_FUNCTION);
		fprintf(outfile,"%s",retstr);
		// Run another code block
		Block(TRUE,FALSE);
		return FALSE;
	}

	if(strcmp(keyword,"END") == 0)							// END keyword
	{
		if(LookToken->type == TK_NEWLINE || LookToken->type == TK_SOFTLINE)	// Plain old END
		{
			strcat(retstr,"exit(0);\n");
			fprintf(outfile,"%s",retstr);
			return FALSE;
		}

		GetToken();
		if(strcmp(curToken->text,"SUB") == 0)				// END SUB keyword
		{
			if(strcmp(curFUNC->name,"MAIN") == 0)
			{
				strcpy(buf,"");
				PrintDepth(buf);
				fprintf(outfile,"%sreturn 0;\n",buf);
			}
			return TRUE;
		}

		if(strcmp(curToken->text,"FUNCTION") == 0)		// END FUNCTION keyword
		{
			strcpy(buf,"");
			PrintDepth(buf);
			fprintf(outfile,"%sreturn %s;\n",buf,curFUNC->name);
			return TRUE;
		}

		if(strcmp(curToken->text,"IF") == 0)				// END IF keyword
			return TRUE;

		if(strcmp(curToken->text,"TYPE") == 0)				// END TYPE keyword
		{
			// Should never get to this
			BASError(LineNumber,"Unexpected keyword 'TYPE'");
			return FALSE;
		}

		if(strcmp(curToken->text,"SELECT") == 0)			// END SELECT keyword
		{
			Keyword_ENDSELECT(retstr);
			fprintf(outfile,"%s",retstr);
			return TRUE;
		}

		//if(strcmp(curToken->text,"DEF") == 0)			// END DEF keyword
			// Unsupported
		//	return FALSE;
		
		return FALSE;			// Should never get to this
	}

	if(strcmp(keyword,"EXIT") == 0)							// EXIT keyword
	{
		GetToken();
		if(strcmp(curToken->text,"SUB") == 0)				// EXIT SUB keyword		
			strcat(retstr,"return;\n");

		if(strcmp(curToken->text,"FUNCTION") == 0)			// EXIT FUNCTION keyword
		{
			strcat(retstr,"return ");
			strcat(retstr,curFUNC->name);
			strcat(retstr,";\n");
		}
		if(strcmp(curToken->text,"FOR") == 0)				// EXIT FOR keyword		
			strcat(retstr,"break;\n");
		if(strcmp(curToken->text,"WHILE") == 0)				// EXIT WHILE keyword
			strcat(retstr,"break;\n");
		if(strcmp(curToken->text,"DO") == 0)				// EXIT DO keyword
			strcat(retstr,"break;\n");
		//if(strcmp(retstr,"DEF") == 0)						// EXIT DEF keyword
			// Unsupported			

		fprintf(outfile,retstr);
		return FALSE;
	}

	if(strcmp(keyword,"IF") == 0)							// IF keyword
	{
		IF_OneLine = Keyword_IF(retstr);
		fprintf(outfile,"%s",retstr);
		Block(TRUE,IF_OneLine);
		return FALSE;
	}

	if(strcmp(keyword,"ELSE") == 0)							// ELSE keyword
	{
		Keyword_ELSE(retstr);
		fprintf(outfile,"%s\n",retstr);
		return FALSE;
	}

	if(strcmp(keyword,"ELSEIF") == 0)						// ELSEIF keyword
	{
		IF_OneLine = Keyword_IF(retstr);
		fprintf(outfile,"%s",retstr);
		Block(TRUE,IF_OneLine);
		return FALSE;
	}

	if(strcmp(keyword,"FOR") == 0)							// FOR keyword
	{
		Keyword_FOR(retstr);
		fprintf(outfile,"%s",retstr);
		Block(TRUE,FALSE);
		return FALSE;
	}

	if(strcmp(keyword,"NEXT") == 0)							// NEXT keyword
	{
		NextLine(TK_SOFTLINE);
		return TRUE;
	}

	if(strcmp(keyword,"WHILE") == 0)							// WHILE keyword
	{
		Keyword_WHILE(retstr);
		fprintf(outfile,"%s",retstr);
		Block(TRUE,FALSE);
		return FALSE;
	}

	if(strcmp(keyword,"WEND") == 0)							// WEND keyword	
		return TRUE;

	if(strcmp(keyword,"GOTO") == 0)							// GOTO keyword
	{
		GetToken();		
		strcat(retstr,"goto ");
		strcat(retstr,curToken->text);
		strcat(retstr,";\n");
		fprintf(outfile,"%s",retstr);
		return FALSE;
	}

	if(strncmp(keyword,"DEF",3) == 0)						// DEF* keywords
	{
		Keyword_DEF(keyword);
		NextLine(TK_SOFTLINE);						// Note: Bugger what variable range it is!
		return FALSE;
	}

	if(strcmp(keyword,"CONST") == 0)							// CONST keyword
	{
		fprintf(outfile,"const ");
		return FALSE;
	}

	if(strcmp(keyword,"DO") == 0)								// DO keyword
	{
		Keyword_DO(retstr);
		fprintf(outfile,"%s",retstr);
		Block(FALSE,FALSE);							// Note: We set group to FALSE coz we don't want
															//       Block() to write the end brace
		return FALSE;
	}

	if(strcmp(keyword,"LOOP") == 0)							// LOOP keyword
	{
		Keyword_LOOP(retstr);
		fprintf(outfile,"%s",retstr);
		return TRUE;
	}

	if(strcmp(keyword,"SELECT") == 0)						// SELECT CASE keyword
	{
		Match("CASE");
		Keyword_SELECTCASE(retstr);
		fprintf(outfile,"%s",retstr);
		Block(TRUE,FALSE);
		return FALSE;
	}

	if(strcmp(keyword,"CASE") == 0)							// CASE keyword
	{
		Keyword_CASE(retstr);
		fprintf(outfile,"%s",retstr);
		return FALSE;
	}

	if(strcmp(keyword,"START_C") == 0)						// START_C keyword
	{
		Keyword_STARTC(retstr);
		fprintf(outfile,"%s",retstr);
		return FALSE;
	}

	if(strcmp(keyword,"START_ASM") == 0)					// START_ASM keyword
	{
		Keyword_STARTASM(retstr);
		fprintf(outfile,"%s",retstr);
		return FALSE;
	}

	if(strcmp(keyword,"READ") == 0)							// READ keyword
	{
		Keyword_READ(retstr);
		fprintf(outfile,"%s",retstr);
		return FALSE;
	}

	if(strcmp(keyword,"DATA") == 0)							// DATA keyword
	{
		// This keyword gets parsed in the first pass
		// so we just ignore it
		NextLine(TK_NEWLINE);
		return FALSE;
	}

	if(strcmp(keyword,"RESTORE") == 0)						// RESTOR keyword
	{
		Keyword_RESTORE(retstr);
		fprintf(outfile,"%s",retstr);
		return FALSE;
	}

	return FALSE;				// Should never get to this (but it prolly does)
}




///////////////////
// Translate 'DECLARE' keyword
void Keyword_DECLARE(char *retstr)
{
	int rettype = VAR_VOID;	
	int functype = FN_SUB;
	char buf[128];	
	int args = 0;
	char argname[81];
	char argtype[81];
	int atyp = 0;
	int UseArgPtr = FALSE;
	func_t *tempfunc = NULL;
	func_t *oldfunc = NULL;
	int Extern = FALSE;
	
	GetToken();

	// Function type
	if(strcmp(curToken->text,"SUB") == 0)
		functype = FN_SUB;
	else if(strcmp(curToken->text,"FUNCTION") == 0)
		functype = FN_FUNCTION;
	else
		BASError(LineNumber,"SUB or FUNCTION expected");	

	// Function name
	GetToken();
	if(strcmp(curToken->text,"EXTERN") == 0)
	{
		Extern = TRUE;
		GetToken();
	}

	oldfunc = curFUNC;
	if(!FindFunction(curToken->text,TRUE))
	{
		sprintf(buf,"Could not find function '%s'\n",curToken->text);
		BASError(LineNumber,buf);
		curFUNC = oldfunc;
		return;
	}
	else	
		rettype = curFUNC->ret;
	
	tempfunc = curFUNC;

	// Check if it's a EXTERN
	if(Extern)
	{
		NextLine(TK_NEWLINE);
		return;
	}
	

	if(functype == FN_SUB)	
		strcat(retstr,"void ");
	else
	{
		Print_VariableType(buf,rettype,tempfunc->retstruct);
		strcat(retstr,buf);
		strcat(retstr," *");
	}

	strcat(retstr,tempfunc->name);
	strcat(retstr,"(");

	Match("(");

	// Arguements
	while(curToken->type != TK_NEWLINE && curToken->type != TK_EOF)
	{
		GetToken();

		if(strcmp(curToken->text,"AS") == 0)
		{
			GetToken();			
			atyp = BASICtypetoCtype(curToken->text,argtype);
			while(curToken->type != TK_NEWLINE)		// Not really until \n, just a precaution
			{
				// Get rid of * and numbers (for fixed length strings)
				if(strcmp(LookToken->text,",") == 0)
					break;
				if(strcmp(LookToken->text,")") == 0)
					break;

				GetToken();
			}
			continue;
		}

		if(strcmp(curToken->text,",") == 0)
		{
			// Print the arguement
			sprintf(buf,"%s *%s, ",argtype,argname);
			strcat(retstr,buf);
			strcpy(argtype,"SINGLE");			// Default
			continue;
		}

		if(strcmp(curToken->text,")") == 0)
		{
			if(args > 0)
			{
				sprintf(buf,"%s *%s",argtype,argname);
				strcat(retstr,buf);
			}
			break;
		}


		// Variable Name
		strcpy(buf,"");
		TranslateVARIABLE(buf,curToken->text);
		strcpy(argname,buf);
		strcpy(argtype,"");
		UseArgPtr = FALSE;
		Print_VariableType(argtype,curToken->VarType,NULL);
		if(curToken->VarType == VAR_STRING || curToken->VarType == VAR_USER_DEFINED)
			UseArgPtr = TRUE;
		args++;
	}

	if(args == 0)
		strcat(retstr,"void");
	strcat(retstr,");\n");
	curFUNC = oldfunc;
}

///////////////////
// Translate "TYPE' keyword
void Keyword_TYPE(char *retstr)
{	
	char buf[128];	
	char memtype[81];
	char member[81];

	GetToken();
	if(strcmp(curToken->text,"EXTERN") == 0)
	{
		// Don't Show it		
		while(strcmp(curToken->text,"END") != 0 && strcmp(LookToken->text,"TYPE") != 0)
			GetToken();

		GetToken();
		return;
	}

	if(!FindType(curToken->text,TRUE))
	{
		sprintf(buf,"Could not find TYPE %s",curToken->text);
		BASError(LineNumber,buf);
		return;
	}

	Match("\n");

	sprintf(buf,"\ntypedef struct %s {\n",curTYPE->name);
	strcat(retstr,buf);

	// Members
	while(strcmp(curToken->text,"END") != 0)
	{
		GetToken();

		if(strcmp(curToken->text,"AS") == 0)
		{			
			GetToken();			
			BASICtypetoCtype(curToken->text,memtype);
			while(LookToken->type != TK_NEWLINE)
			{
				// Get rid of * and numbers (for fixed length strings)
				GetToken();
			}
			continue;
		}
		
		if(curToken->type == TK_NEWLINE)
		{
			sprintf(buf,"   %s %s;\n",memtype,member);
			strcat(retstr,buf);
			continue;
		}

		if(strcmp(curToken->text,"END") == 0 && strcmp(LookToken->text,"TYPE") == 0)
			break;		
		
		strcpy(member,"");		
		TranslateVARIABLE(member,curToken->text);		
	}

	if(strcmp(LookToken->text,"TYPE") == 0)
		GetToken();

	sprintf(buf,"} %s;\n\n",curTYPE->name);
	strcat(retstr,buf);
}

///////////////////
// Translates a 'DIM' keyword
void Keyword_DIM(char *retstr)
{
	char name[128];
	char buf[128];
	char type[81];
	int VarType = DefStruct->DefaultType;
	var_t tempvar;
	int IsArray = FALSE;
		
	while(curToken->type != TK_EOF)			// Precautionary check, should NEVER get to EOF here
	{
		GetToken();

		if(strcmp(curToken->text,"SHARED") == 0)
			continue;
		if(strcmp(curToken->text,"EXTERN") == 0)
		{
			// Don't show it
			NextLine(TK_NEWLINE);
			return;
		}

		if(strcmp(curToken->text,"AS") == 0)
		{
			GetToken();
			BASICtypetoCtype(curToken->text,type);			
			continue;
		}

		// Next Definition
		if(strcmp(curToken->text,",") == 0)
		{
			IsArray = FALSE;			
			if(tempvar.flags & VRF_ARRAY)
				IsArray = TRUE;

			if(VarType == VAR_STRING && !IsArray)
				sprintf(buf,"%s %s = NewString();\n",type,name);
			else if(VarType != VAR_USER_DEFINED && !IsArray)
				sprintf(buf,"%s %s = 0;\n",type,name);
			else
				sprintf(buf,"%s %s;\n",type,name);

			strcat(retstr,buf);
			continue;
		}

		if(curToken->type == TK_NEWLINE)
		{
			IsArray = FALSE;		
			if(tempvar.flags & VRF_ARRAY)
				IsArray = TRUE;

			if(VarType == VAR_STRING && !IsArray)
				sprintf(buf,"%s %s = NewString();\n",type,name);
			else if(VarType != VAR_USER_DEFINED && !IsArray)
				sprintf(buf,"%s %s = 0;\n",type,name);
			else
				sprintf(buf,"%s %s;\n",type,name);

			strcat(retstr,buf);
			break;
		}

		if(strcmp(curToken->text,"*") == 0)
		{
			while(1)
			{
				GetToken();
				if(strcmp(LookToken->text,",") == 0 || LookToken->type == TK_NEWLINE)
					break;
			}			
			continue;
		}
		
		// Variable Name
		strcpy(name,"");
		strcpy(type,"");
		VarType = curToken->VarType;
		if(!FindVariable(curToken->text,&tempvar))
		{
			sprintf(buf,"Could not find variable '%s'",curToken->text);
			SysError(__LINE__,"Keyword_DIM",buf);
		}
		Print_VariableType(type,curToken->VarType,NULL);
		TranslateVARIABLE(name,curToken->text);		
	}
}

///////////////////
// Translates a SUB or FUNCTION keyword
void Keyword_SUB(char *retstr,int type)
{
	char name[256];
	int rettype = VAR_VOID;
	char buf[128];
	char temp[128];
	char retstring[81];
	char argtype[128];
	char argname[81];
	int args = 0;
	var_t *poldvar = NULL;
	int UseArgPtr = FALSE;
	int atyp = 0;

	Indent = 0;				// Reset it
	
	GetToken();
	strcpy(name,curToken->text);
	if(!FindFunction(name,TRUE))
	{
		sprintf(buf,"SUB/FUNCTION '%s' not defined",name);
		BASError(LineNumber,buf);
		return;
	}

	// Check if it's the MAIN sub, if so, change it slightly
	if(strcmp(name,"MAIN") == 0)
	{
		strcat(retstr,"int main(int argc, char *argv[])\n");
		strcat(retstr,"{\n");
		ADD_DEPTH
		NextLine(TK_NEWLINE);
	
		// Variables
		poldvar = curFUNC->vars;
		while(poldvar->prev != NULL)
			poldvar = poldvar->prev;

		while(poldvar != NULL)
		{
			if(strcmp(poldvar->name,"") != 0 && !(poldvar->flags & VRF_DIMMED))
			{			
				strcpy(buf,"");
				strcpy(temp,"");
				Print_VariableType(buf,poldvar->type,poldvar->structtype);
				PrintDepth(temp);			
				strcat(retstr,temp);
				strcat(retstr,buf);
				strcat(retstr," ");
				strcat(retstr,poldvar->name);
				if(poldvar->type != VAR_STRING && poldvar->type != VAR_USER_DEFINED)
					strcat(retstr," = 0");
				if(poldvar->type == VAR_STRING)
					strcat(retstr," = NewString()");
				
				strcat(retstr,";\n");
			}
			poldvar = poldvar->next;
		}

		return;
	}
	
	rettype = curFUNC->ret;
	strcpy(retstring,"");
	Print_VariableType(retstring,rettype,curFUNC->retstruct);
	if(rettype == VAR_VOID)
		sprintf(buf,"\n%s %s(",retstring,curFUNC->name);
	else
		sprintf(buf,"\n%s *%s(",retstring,curFUNC->name);
	strcat(retstr,buf);

	GetToken();	

	// Arguements	
	while(curToken->type != TK_NEWLINE && curToken->type != TK_EOF)
	{
		GetToken();

		if(strcmp(curToken->text,"AS") == 0)
		{
			GetToken();			
			atyp = BASICtypetoCtype(curToken->text,argtype);
			while(curToken->type != TK_NEWLINE)		// Not really until \n, just a precaution
			{
				// Get rid of * and numbers (for fixed length strings)
				if(strcmp(LookToken->text,",") == 0)
					break;
				if(strcmp(LookToken->text,")") == 0)
					break;

				GetToken();
			}
			continue;
		}

		if(strcmp(curToken->text,",") == 0)
		{
			// Print the arguement			
			sprintf(buf,"%s *%s, ",argtype,argname);
			strcat(retstr,buf);
			strcpy(argtype,"SINGLE");			// Default
			continue;
		}

		if(strcmp(curToken->text,")") == 0)
		{
			if(args > 0)
			{
				sprintf(buf,"%s *%s",argtype,argname);
				strcat(retstr,buf);				
			}
			break;
		}

		if(strcmp(curToken->text,"(") == 0)
			continue;

		// Variable Name
		strcpy(buf,"");
		TranslateVARIABLE(buf,curToken->text);
		strcpy(argname,buf);
		UseArgPtr = FALSE;
		strcpy(argtype,"");
		Print_VariableType(argtype,curToken->VarType,NULL);
		if(curToken->VarType == VAR_STRING || curToken->VarType == VAR_USER_DEFINED)
			UseArgPtr = TRUE;
		args++;
	}

	if(args == 0)
		strcat(retstr,"void");
	
	strcat(retstr,")\n{\n");	
	ADD_DEPTH	

	if(type == FN_FUNCTION)
	{
		// Return value variable
		strcpy(retstring,"");
		Print_VariableType(retstring,rettype,curFUNC->retstruct);	
		PrintDepth(retstr);
		if(rettype == VAR_STRING)
			sprintf(buf,"%s *%s = NewPTRString();\n",retstring,curFUNC->name);
		else
			sprintf(buf,"%s *%s = (%s *)GetPointer(sizeof(%s));\n",retstring,curFUNC->name,retstring,retstring);
		strcat(retstr,buf);
	}

	// Variables
	poldvar = curFUNC->vars;
	while(poldvar->prev != NULL)
		poldvar = poldvar->prev;

	while(poldvar != NULL)
	{
		if(strcmp(poldvar->name,"") != 0 && !(poldvar->flags & VRF_DIMMED))
		{			
			strcpy(buf,"");
			strcpy(temp,"");
			Print_VariableType(buf,poldvar->type,poldvar->structtype);
			PrintDepth(temp);			
			strcat(retstr,temp);
			strcat(retstr,buf);
			strcat(retstr," ");
			strcat(retstr,poldvar->name);
			if(poldvar->type != VAR_STRING && poldvar->type != VAR_USER_DEFINED)
				strcat(retstr," = 0");			
			if(poldvar->type == VAR_STRING)
				strcat(retstr," = NewString()");

			strcat(retstr,";\n");
		}
		poldvar = poldvar->next;
	}
}

///////////////////
// Translates a 'IF' keyword
int Keyword_IF(char *retstr)
{
	int IsString = FALSE;
	char IFString[1024];
	int OneLine = TRUE;
	
	strcpy(IFString,"");

	IsString = Condition(IFString);

	if(strcmp(curToken->text,"THEN") == 0)
		if(LookToken->type == TK_NEWLINE)
			OneLine = FALSE;
	
	strcat(retstr,"if(");
	strcat(retstr,IFString);
	strcat(retstr,")\n");	
	PrintDepth(retstr);
	strcat(retstr,"{\n");
	ADD_DEPTH

	return OneLine;
}

///////////////////
// Translates a 'ELSE' keyword
void Keyword_ELSE(char *retstr)
{
	SUB_DEPTH
	strcat(retstr,"\n");
	PrintDepth(retstr);
	strcat(retstr,"}\n");

	PrintDepth(retstr);
	strcat(retstr,"else\n");
	PrintDepth(retstr);
	strcat(retstr,"{");
	ADD_DEPTH
}

///////////////////
// Translates a 'FOR' keyword
void Keyword_FOR(char *retstr)
{
	int UseStep = FALSE;

	// Start Variable
	strcat(retstr,"FOR(");
	Expression(retstr,FALSE,FALSE,FALSE);

	// Start Value
	Match("=");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,FALSE);

	Match("TO");
	strcat(retstr,",");
	Expression(retstr,FALSE,FALSE,FALSE);

	
	// STEP (optional)
	strcat(retstr,",");
	if(strcmp(LookToken->text,"STEP") == 0)
	{
		GetToken();
		Expression(retstr,FALSE,FALSE,FALSE);
	}
	else
		strcat(retstr,"1");

	strcat(retstr,")\n");
	// No Start brace coz the FOR macro's got it's own start brace
	ADD_DEPTH
}

///////////////////
// Translates a 'WHILE' statement
void Keyword_WHILE(char *retstr)
{
	char WhileString[1024];

	strcpy(WhileString,"");

	Condition(WhileString);	
	
	strcat(retstr,"while(");
	strcat(retstr,WhileString);
	strcat(retstr,")\n");	
	PrintDepth(retstr);
	strcat(retstr,"{\n");
	ADD_DEPTH
}

///////////////////
// Translates a 'DO' keyword
void Keyword_DO(char *retstr)
{
	int UseWhile = FALSE;
	int UseUntil = FALSE;	

	if(strcmp(LookToken->text,"WHILE") == 0)
	{
		UseWhile = TRUE;
		GetToken();
	}
	if(strcmp(LookToken->text,"UNTIL") == 0)
	{
		UseUntil = TRUE;
		GetToken();
	}

	if(!UseWhile && !UseUntil)
	{
		strcat(retstr,"do\n");
		PrintDepth(retstr);
		strcat(retstr,"{\n");
		ADD_DEPTH
		return;
	}

	strcat(retstr,"while(");
	if(UseUntil)
		strcat(retstr,"!(");

	Condition(retstr);

	if(UseUntil)
		strcat(retstr,")");
	strcat(retstr,")\n");
	PrintDepth(retstr);
	strcat(retstr,"{\n");
	ADD_DEPTH
}

///////////////////
// Translates a 'LOOP' keyword
void Keyword_LOOP(char *retstr)
{

	// NOTE: We specified that a 'DO' loop is NOT a group, so we must close the block
	//			manually

	int UseWhile = FALSE;
	int UseUntil = FALSE;	

	if(strcmp(LookToken->text,"WHILE") == 0)
	{
		UseWhile = TRUE;
		GetToken();
	}
	if(strcmp(LookToken->text,"UNTIL") == 0)
	{
		UseUntil = TRUE;
		GetToken();
	}

	if(UseWhile || UseUntil)	
	{
		SUB_DEPTH
		strcat(retstr,"\n");
		PrintDepth(retstr);
		strcat(retstr,"} while(");
		if(UseUntil)
			strcat(retstr,"!(");

		Condition(retstr);

		if(UseUntil)
			strcat(retstr,")");
		strcat(retstr,");\n");		
		return;
	}
	
	SUB_DEPTH
	strcat(retstr,"\n");
	PrintDepth(retstr);
	strcat(retstr,"}\n");
}

///////////////////
// Translates a 'SELECT CASE' keyword
void Keyword_SELECTCASE(char *retstr)
{
	// Setup the SelStruct
	SelStruct->InSelectBlock = TRUE;
	strcpy(SelStruct->expr,"");
	SelStruct->VarType = Expression(SelStruct->expr,FALSE,FALSE,FALSE);
	IsCase = FALSE;
}

///////////////////
// Translates a 'CASE' keyword
void Keyword_CASE(char *retstr)
{
	char Expr[4096];
	strcpy(Expr,"");

	if(!SelStruct->InSelectBlock)
		BASError(LineNumber,"CASE keyword is not in a SELECT CASE Block!");

	if(IsCase)
	{
		SUB_DEPTH
		strcat(retstr,"\n");
		PrintDepth(retstr);
		strcat(retstr,"}\n");
		PrintDepth(retstr);
	}
	else
	{
		strcat(retstr,"\n");
		PrintDepth(retstr);
	}

	IsCase = TRUE;
	
	
	// Not Supported (maybe)?
	if(strcmp(LookToken->text,"ELSE") == 0)
	{
		//Match("ELSE");
		//strcat(retstr,"case default:\n");
		//ADD_DEPTH
		return;
	}
		
	strcat(retstr,"if(");
	if(SelStruct->VarType)
		strcat(retstr,"strcmp(");

	strcat(retstr,SelStruct->expr);

	if(SelStruct->VarType)
		strcat(retstr,",");
	else
		strcat(retstr," == ");

	Expression(Expr,FALSE,FALSE,FALSE);

	strcat(retstr,Expr);
	strcat(retstr,")");

	if(SelStruct->VarType)
		strcat(retstr," == 0)");

	strcat(retstr,"\n");

	PrintDepth(retstr);
	strcat(retstr,"{\n");
	ADD_DEPTH
}

///////////////////
// Translates a 'END SELECT' keyword
void Keyword_ENDSELECT(char *retstr)
{
	SelStruct->InSelectBlock = FALSE;
	IsCase = FALSE;
	strcat(retstr,"\n");
}

///////////////////
// Translates 'DEF***' keywords
void Keyword_DEF(char *name)
{
	char type[8];
	if(strcmp(LookToken->text,"SEG") == 0 ||
		strcmp(LookToken->text,"FN") == 0)
	{
		GetToken();
		return;										// Ignore these
	}

	strcpy(type,strdup(name+3));
	if(strcmp(type,"INT") == 0)
		DefStruct->DefaultType = VAR_INTEGER;
	if(strcmp(type,"SNG") == 0)
		DefStruct->DefaultType = VAR_SINGLE;
	if(strcmp(type,"DBL") == 0)
		DefStruct->DefaultType = VAR_DOUBLE;
	if(strcmp(type,"LNG") == 0)
		DefStruct->DefaultType = VAR_LONG;
	if(strcmp(type,"STR") == 0)
		DefStruct->DefaultType = VAR_STRING;
}

///////////////////
// Translates 'START_C' keyword
void Keyword_STARTC(char *retstr)
{
	// Piece o' piss
	char c;
	int quitloop = FALSE;
	char EndC[] = {"END_C"};	
	unsigned int n;
	char Stock[10];
	
	while(!quitloop)
	{
		c = yyinput();
		if(c == '\n')
			LineNumber++;

		if(c == EndC[0])
		{			
			Stock[0] = c;
			for(n=1;n<strlen(EndC);n++)
			{
				c = yyinput();
				Stock[n] = c;
				if(c != EndC[n])
				{
					Stock[n+1] = '\0';
					strcat(retstr,Stock);
					break;
				}
				if(n == strlen(EndC)-1)
				{
					quitloop = TRUE;
					break;
				}
			}
		}
		else
		{
			sprintf(Stock,"%c",c);
			strcat(retstr,Stock);
		}
	}

	FileStart = TRUE;	
	GetToken();
	LineNumber++;
}

///////////////////
// Translates 'START_ASM' keyword
void Keyword_STARTASM(char *retstr)
{
	// Piece o' piss
	char c;
	int quitloop = FALSE;
	char EndAsm[] = {"END_ASM"};
	unsigned int n;
	char Stock[10];
	
	strcat(retstr,"__asm {\n");
	
	while(!quitloop)
	{
		c = yyinput();
		if(c == '\n')
			LineNumber++;
		
		if(c == EndAsm[0])
		{			
			Stock[0] = c;
			for(n=1;n<strlen(EndAsm);n++)
			{
				c = yyinput();
				Stock[n] = c;
				if(c != EndAsm[n])
				{
					Stock[n+1] = '\0';
					strcat(retstr,Stock);
					break;
				}
				if(n == strlen(EndAsm)-1)
				{
					quitloop = TRUE;
					break;
				}
			}
		}
		else
		{
			sprintf(Stock,"%c",c);
			strcat(retstr,Stock);
		}
	}

	FileStart = TRUE;
	GetToken();
	strcat(retstr,"\n");
	PrintDepth(retstr);
	strcat(retstr,"}\n");
}

///////////////////
// Translates a 'READ' keyword
void Keyword_READ(char *retstr)
{
	// Same style as INPUT & PRINT functions
	
	char fmt[256];
	char args[4096];
	char buf[512];
	var_t VarStruct;

	strcpy(fmt,"\"");
	strcpy(args,"");

	strcat(retstr,"READ(__DATA__,");

	GetToken();
	while(curToken->type != TK_NEWLINE && 
		curToken->type != TK_SOFTLINE && 
		curToken->type != TK_EOF)
	{
		if(curToken->type != TK_VARIABLE)		
			BASError(LineNumber,"Expected Variable");

		strcpy(buf,"");
		VarStruct = TranslateVARIABLE(buf,curToken->text);
		if(!(VarStruct.flags & VRF_POINTER))
			strcat(args,"&");
		strcat(args,buf);
		switch(VarStruct.type)
		{
			case VAR_STRING:
				strcat(fmt,"s");
				break;
			case VAR_INTEGER:
			case VAR_LONG:
				strcat(fmt,"i");
				break;
			case VAR_SINGLE:
			case VAR_DOUBLE:
				strcat(fmt,"f");
				break;
			case VAR_USER_DEFINED:
				BASError(LineNumber,"Cannot parse structures to READ statement");
				break;
		}

		if(strcmp(LookToken->text,",") == 0)
			GetToken();
		strcat(args,",");
		GetToken();
	}
	
	// Remove ending comma
	args[strlen(args)-1] = '\0';
	strcat(retstr,fmt);
	strcat(retstr,"\",");
	strcat(retstr,args);
	strcat(retstr,");\n");
}

///////////////////
// Translates a 'RESTORE' keyword
void Keyword_RESTORE(char *retstr)
{
	strcat(retstr,"RESTORE(\"");

	GetToken();
	if(curToken->type == TK_NEWLINE ||
	   curToken->type == TK_SOFTLINE ||
	   curToken->type == TK_EOF)
	{
		strcat(retstr,"-1\");\n");
		return;
	}

	if(curToken->type != TK_UNKNOWN && 
		curToken->type != TK_NUMBER && 
		curToken->type != TK_VARIABLE)
	{
		BASError(LineNumber,"Expected label or line number");
	}

	strcat(retstr,curToken->text);
	strcat(retstr,"\");\n");
}