/*                      QBCC Project

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

*/
// Variable Output

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


///////////////////
// Translate the Variable
var_t TranslateVARIABLE(char *retstr,char *name)
{
	char Expr[1024];
	char varname[81];
	int IsArray = FALSE;
	int temptype = 0;
	int VarType = DefStruct->DefaultType;
	char buf[128];
	type_t *type = NULL;
	var_t variable;
	int GotVar = FALSE;
	var_t RetVar;
	int vtype = 0;
	func_t *poldfunc = NULL;

	if(IsVariable(name,&VarType))
		vtype = 1;
	else	
		if(IsArguement(name,&VarType))
			vtype = 2;
		else
			if(IsMember(name,&VarType))
				vtype = 3;
			else
				if(FindFunction(name,FALSE))
					vtype = 4;

	if(vtype == 0)
	{
		sprintf(buf,"Cannot find variable %s",name);
		SysError(__LINE__,"TranslateVARIABLE",buf);
	}

	strcpy(varname,name);
	strcat(retstr,name);

	switch(vtype)
	{
		case 1:
			FindVariable(varname,&variable);
			break;
		case 2:
			FindArguement(varname,&variable);
			break;
		case 3:
			FindMember(varname,&variable);
			break;
		case 4:
			poldfunc = curFUNC;
			FindFunction(varname,TRUE);
			variable.type = curFUNC->ret;
			variable.structtype = curFUNC->retstruct;
			variable.flags |= VRF_POINTER;
			curFUNC = poldfunc;
			break;
	}
	

	type = variable.structtype;
	RetVar = variable;

	if(strcmp(LookToken->text,"(") == 0)			// Array
	{
		IsArray = TRUE;
		while(curToken->type != TK_NEWLINE)				// \n as a precaution
		{
			GetToken();		
			if(strcmp(curToken->text,"(") == 0)		
			{
				strcat(retstr,"[");
				
				strcpy(Expr,"");
				Expression(Expr,FALSE,FALSE,FALSE);
				if(strcmp(LookToken->text,"TO") == 0)		// Handle those obsolete 'TO' keywords
				{
					Match("TO");
					strcpy(Expr,"");
					Expression(retstr,FALSE,FALSE,FALSE);
				}
				
				strcat(retstr,Expr);

				continue;
			}

			if(strcmp(curToken->text,")") == 0)
			{			
				strcat(retstr,"]");
				break;
			}

			if(strcmp(curToken->text,",") == 0)
			{
				strcat(retstr,"][");
				strcpy(Expr,"");
				Expression(Expr,FALSE,FALSE,FALSE);
				if(strcmp(LookToken->text,"TO") == 0)		// Handle those obsolete 'TO' keywords
				{
					Match("TO");
					strcpy(Expr,"");
					Expression(retstr,FALSE,FALSE,FALSE);
				}
				
				strcat(retstr,Expr);
				continue;
			}
		}
	}	
		
	// Check if a member follows
	if(LookToken->type != TK_DOT)
		return RetVar;
	
	if(type)
	{		
		if(!FindType(type->name,TRUE))
		{
			sprintf(buf,"TYPE '%s' not found",varname);
			BASError(LineNumber,buf);
		}
	}	

	Match(".");

	GetToken();		// Member	

	if(IsArguement(varname,&temptype))
	{
		if(IsArray)
			strcat(retstr,".");
		else
			strcat(retstr,"->");
	}
	else
		strcat(retstr,".");

	// TODO: Check it is a member	
	return TranslateVARIABLE(retstr,curToken->text);
}

///////////////////
// Prints the variable type
void Print_VariableType(char *retstr, int type, type_t *structtype)
{	
	switch(type)
	{
		case VAR_INTEGER:
			strcpy(retstr,DefStruct->INTEGER); break;
		case VAR_SINGLE:
			strcpy(retstr,DefStruct->SINGLE); break;
		case VAR_DOUBLE:
			strcpy(retstr,DefStruct->DOUBLE); break;
		case VAR_LONG:
			strcpy(retstr,DefStruct->LONG); break;
		case VAR_STRING:
			strcpy(retstr,DefStruct->STRING); break;		
		case VAR_VOID:
			strcpy(retstr,"void"); break;
		case VAR_FILE:
			strcpy(retstr,DefStruct->FILE); break;
		case VAR_USER_DEFINED:
			if(structtype)
				strcpy(retstr,structtype->name); 
			break;
	}
}

///////////////////
// Converts a BASIC type to a C type (text compare)
int BASICtypetoCtype(char *basict,char *ct)
{
	if(strcmp(basict,"INTEGER") == 0)
	{
		strcpy(ct,DefStruct->INTEGER);
		return VAR_INTEGER;
	}
	if(strcmp(basict,"SINGLE") == 0)
	{
		strcpy(ct,DefStruct->SINGLE);
		return VAR_SINGLE;
	}
	if(strcmp(basict,"DOUBLE") == 0)
	{
		strcpy(ct,DefStruct->DOUBLE);
		return VAR_DOUBLE;
	}
	if(strcmp(basict,"STRING") == 0)
	{
		strcpy(ct,DefStruct->STRING);
		return VAR_STRING;
	}
	if(strcmp(basict,"LONG") == 0)
	{
		strcpy(ct,DefStruct->LONG);
		return VAR_LONG;
	}

	// Must be a user defined type
	strcpy(ct,basict);
	return VAR_USER_DEFINED;
}

///////////////////
// Prints the global Variables
void Print_DevCSummary(void)
{
	var_t *poldvar;
	char type[64];
	type_t *poldtype;
	func_t *poldfunc;

#ifdef _DEV_
	printf("- Printing Global Variables & Structures\n");
#endif

	fprintf(outfile,"\n/* ---- Structures ---- */\n");
	poldtype = curTYPE;
	while(poldtype->prev != NULL)
		poldtype = poldtype->prev;
	
	while(poldtype != NULL)
	{
		if(strcmp(poldtype->name,"") != 0)
		{
			fprintf(outfile,"typedef struct %s_s {\n",poldtype->name);
			poldvar = poldtype->vars;
			while(poldvar->prev != NULL)
				poldvar = poldvar->prev;

			while(poldvar != NULL)
			{
				if(strcmp(poldvar->name,"") != 0)
				{
					Print_VariableType(type,poldvar->type,poldvar->structtype);
					fprintf(outfile,"   %s %s;\n",type,poldvar->name);
				}
				poldvar = poldvar->next;
			}

			fprintf(outfile,"} %s;\n\n",poldtype->name);
		}
		poldtype = poldtype->next;
	}

	fprintf(outfile,"\n/* ---- Global Variables ---- */\n");

	FindFunction("__BC_GLOBAL__",TRUE);
	poldvar = curFUNC->vars;

	while(poldvar->prev != NULL)
		poldvar = poldvar->prev;

	while(poldvar != NULL)
	{
		if(strcmp(poldvar->name,"") != 0 && !(poldvar->flags & VRF_ARRAY))
		{
			Print_VariableType(type,poldvar->type,poldvar->structtype);
			strcat(type," ");
			strcat(type,poldvar->name);		
			fprintf(outfile,"%s;\n",type);
		}
		poldvar = poldvar->next;
	}
	
	fprintf(outfile,"\n/* ---- Prototypes ---- */\n");
	if(curFUNC->next)
		poldfunc = curFUNC->next;
	else
		return;
	while(poldfunc != NULL)
	{
		Print_VariableType(type,poldfunc->ret,poldfunc->retstruct);
		fprintf(outfile,"%s %s(",type,poldfunc->name);

		poldvar = poldfunc->args;
		while(poldvar->prev != NULL)
			poldvar = poldvar->prev;
	
		while(poldvar != NULL)
		{
			if(strcmp(poldvar->name,"") != 0)
			{
				Print_VariableType(type,poldvar->type,poldvar->structtype);
				strcat(type," ");
				if(poldvar->flags & VRF_ARRAY)
					strcat(type,"*");
				strcat(type,poldvar->name);
				fprintf(outfile,"%s",type);

				if(poldvar->next)
					fprintf(outfile,",");
			}
			poldvar = poldvar->next;
		}
		fprintf(outfile,");\n");

		poldfunc = poldfunc->next;
	}
}
