#include "interpreter.h"


//	**********************************************
//	********   The interpreter class  ************
//	**********************************************
//public methods:
Interpreter::Interpreter()
{	
	debugModeStatus = false;
	programReadyForExecution = false;
}

bool Interpreter::executeProgram(vector<string> & sourceProgram)
{		
		//If program not ready for execution yet,
		//	rebuild the lexical, syntactic, and semantic information first.
		if	(	isProgramReadyForExecution() == false	)
		{
			//First clear all the existing information
			mySyntax.clearAllLexicalSyntacticSemanticInfo(); 

			if	(	mySyntax.parseSourceCode(sourceProgram) )	
				//If everything is fine, ready for execution now
				setProgramStatusAsReadyForExecution();
			else
			{	cout << "Syntax Errors detected.!" << endl
					 << "Cannot execute the function call." << endl;
				return false;
			}
		}


		if ( isDebugModeOn() )
		{
			mySyntax.displayAllInterpreterInstructions();
			mySyntax.displayMapForNextInterpreterInstruction();
			mySyntax.displayFunctionCodeRecords();
		}


		mySyntax.displayFunctionPrototypes();
		cout << endl 
			 << "Enter a function call in the form of :"	<< endl
			 << "yourFunctionName(yourArgument1, yourArgument2,...)"	
			 << endl << endl;

		string command;
		while ( command.empty() )
			cin >> command;


		string functionName; 
		vector<float> argumentsList;
		if (getCommandString(command, functionName, argumentsList) == false )
		//Parse the command to get the function name and the arguments.
		//If not a valid command to execute the program.
		//	try to to call main() instead.
		{	cout	<< endl << endl 
					<< "Cannot execute the function call: " << command
					<< endl << endl;

		}

		cout << endl << endl
			 << "*****************************************************" << endl
			 << "****  Now executing function call: " << functionName <<"(";
		if ( argumentsList.size()>0 ) 
		{	for (size_t i=0; i<argumentsList.size()-1; ++i)
				cout << argumentsList[i] <<",";

			cout << argumentsList.back();	//The last argument
		}
		cout << ')'<< endl 
			 << "*****************************************************" << endl
			 << endl << endl;

		float returnValue;
		if (executeFunctionCall(functionName, argumentsList, returnValue))
			cout	<< endl << endl 
					<< command	<< " ==> " << returnValue << endl << endl;
		else
			cout	<< endl << endl 
					<< "The function call: " << command
					<< " fails to finish! " << endl << endl;

		cout << "*****************************************************" << endl
			 << "*********       End of function call       **********" << endl
			 << "*****************************************************" << endl
			 << endl;

		cout << endl;
}


void Interpreter::outputParseTree(vector<string> & sourceProgram, const char * outputFileName)
{
	if (!programReadyForExecution)
	{
			//First clear all the existing information
			mySyntax.clearAllLexicalSyntacticSemanticInfo(); 

			if	(	mySyntax.parseSourceCode(sourceProgram) )	
				//If everything is fine, ready for execution now
				setProgramStatusAsReadyForExecution();
			else
			{	cout << "Syntax Errors detected.!" << endl
					 << "Cannot execute the function call." << endl;
				return;
			}
	}

	mySyntax.outputParseTree(outputFileName);

};

//Do the evaluation and output all the things a a display statement.
//	If somthing wrong in the execution, return true; 
//	othersie return false.
bool Interpreter::executeDisplayInterpreterInstruction
(	perLineTokenVector & thisInterpreterInstruction,
	symbolTable & localVariablesTable
)
{
			//***************************************
			//***     Add your own code here      ***
			//***************************************

	return true;

}





//********************************************************************
//*****		Private member functions for program execution		******
//********************************************************************
bool Interpreter::executeFunctionCall	
(	string functionName, 
	vector<float> argumentsList,
	float & result
)
{	
	if ( isDebugModeOn() )
	{
		cout << endl
			 << "Start executing the function call:"
			 << functionName << "(";

		if ( argumentsList.size()>0 ) 
		{	for (size_t i=0; i<argumentsList.size()-1; ++i)
				cout << argumentsList[i] <<",";
			cout << argumentsList.back();
		}
		cout << ")"<< endl << endl;
	}

	if (	mySyntax.tableOfFunctionNamesAndCodeRecords.find(functionName)
			== mySyntax.tableOfFunctionNamesAndCodeRecords.end()
	   )
	   //If there is no function of that name found in the table of function names
	   //	and codeFunctionRecords, return false.
		{
			breakPoint("Error. Call to an unknown function:"+functionName);
			cout << endl;
			return false;
		}
	else if (	argumentsList.size() != 
				mySyntax.tableOfFunctionNamesAndCodeRecords[functionName].parametersList.size()
			)
	    //If the number of arguments in the function call
		//	does not match the number of parameters of the functionCodeRecord
		//	found with the same name in the tableOfFunctionNamesAndCodeRecords, 
		//just return false.
		{
			breakPoint("Error. The number of arguments not right when calling function:"
						+functionName);
			cout << endl;
			return false;
		}


	//Now we have determined this is a valid function call,
	//	we make a duplicate of the corresponding functionCodeRecord and 
	//	activate it as a new functionCodeRecord on top of 
	//	the stack of activated function code records.
	//And when we execute this particular function call, we will use the
	//	localVariablesTable associated with this copy of functionCodeRecord.
	//This allows us to deal with recursive function calls, and
	//	makes it easy to trace this stack at any point at time
	//	to see the thread of function calls and the current values of 
	//	local variables within the context of these function calls.
	stackOfActivatedFunctionCodeRecords.push_back
		( mySyntax.tableOfFunctionNamesAndCodeRecords[functionName] );

	//For convenience, create aniterator to this functionCodeRcord, which
	//	is on top of the stack (i.e. the last element of the vector container)
	list<functionCodeRecord>::reverse_iterator itrToThisCodeRecord
		= stackOfActivatedFunctionCodeRecords.rbegin();

	//Copy the arguments as initial values of the corresponding parameters
	for (size_t i=0; i < argumentsList.size(); ++i)
		itrToThisCodeRecord->
			localVariablesTable[ itrToThisCodeRecord->parametersList[i] ] 
			= argumentsList[i];

	//Also make a copy of the arguments into the code record
	itrToThisCodeRecord->argumentsList = argumentsList;

	//Execute interpreter instructions corresponding to this function one by one
	//	use the localVariablesTable associated with the newly activated copy of 
	//	functionCodeRrecord on the top of the stack of activated functionCodeRecords
	int indexOfInterpreterInstructionToExecute
				= itrToThisCodeRecord->indexOfFirstInterpreterInstruction;
	while (	executeOneMoreInterpreterInstruction
				(	indexOfInterpreterInstructionToExecute, 
					itrToThisCodeRecord->localVariablesTable,
					result
				)
			//Execute one more instruction and the return value tells us whether
			//	we should continue execution after that.
		  )
	{
		//Determine what is the next intrction to continue 
		indexOfInterpreterInstructionToExecute
			=	getIndexNextInterpreterInstructionToExecute
				(	indexOfInterpreterInstructionToExecute,
					itrToThisCodeRecord->localVariablesTable
				);

		if (	indexOfInterpreterInstructionToExecute > 
				itrToThisCodeRecord->indexOfLastInterpreterInstruction
		   )
		{	breakPoint("Error. Execution jump out of the the function "+functionName);
			cout << endl << endl;
			//Remove the activated functionCodeRecord from the stack
			//	before we return from the function call

			stackOfActivatedFunctionCodeRecords.pop_back();
			//Remove the activated functionCodeRecord from the stack
			//	before we return from the function call

			return false;
		}
		
	}

	if ( isDebugModeOn() )
	{
		cout << "Now finishing the function call:"
			 << functionName << "(";

		if ( argumentsList.size()>0 ) 
		{	for (size_t i=0; i<argumentsList.size()-1; ++i)
				cout << argumentsList[i] <<",";
			cout << argumentsList.back();
		}
		cout << ")"<< endl << endl;

		displayStackOfActivatedFunctionCodeRecords();

	}

	stackOfActivatedFunctionCodeRecords.pop_back();
	//Remove the activated functionCodeRecord from the stack
	//	before we return from the function call

	return true;
}
//Execute a function call to a function with functionNamethe as name 
//	and argumentsList as the values of the parameters.
//If the function call is correctly finished, return true and 
//	store the return value of the call in result;
//otherwise, return false.
//
//The functions below are used in the implementation for this function.


bool Interpreter::executeOneMoreInterpreterInstruction
(	int indexThisInterpreterInstruction, 
	symbolTable & localVariablesTable,
	float & result
)
//Execute one interpreter instruction with respect to 
//	a table of local variables table.
//Return false and store the return value in result
//	if reaching a return statement or the end of function;
//Otherwise, simply return true in the end.
{	
	vector<string> thisInterpreterInstruction
			= mySyntax.vectInterpreterInstructions[indexThisInterpreterInstruction];
	if (	isDebugModeOn() )
	{
		mySyntax.displayOneInterpreterInstruction(thisInterpreterInstruction);
		breakPoint("\tNow executing the interpreter instruction above");
	}

	interpreterInstructionCategory
		thisInterpreterInstructionCategory
		= mySyntax.categoryVectOfAllInterpreterInstructions[indexThisInterpreterInstruction];


	switch (thisInterpreterInstructionCategory)
	{	float expressionValue;

		case DISPLAY_STATEMENT:		 //e.g. display x+y;
			//***************************************
			//***     Add your own code here      ***
			//***************************************
			break;

		case ASSIGNMENT_STATEMENT:				 //e.g. x=1+y;
			//***************************************
			//***     Add your own code here      ***
			//***************************************

			break;

		case READ_STATEMENT:					 //e.g. read x;
			//***************************************
			//***     Add your own code here      ***
			//***************************************

			break;

		case RETURN_STATEMENT:		//e.g. return x-1;
			//***************************************
			//***     Add your own code here      ***
			//***************************************

			return false;	
			//In this case, we must Stop executing next interpreter instruction
			break;

		case END_FUNCTION_DEFINTION_BLOCK: //;
			//***************************************
			//***     Add your own code here      ***
			//***************************************
			return false;	
			//In this case, we must Stop executing next interpreter instruction
			break;

		case FUNCTION_CALL_ASSIGNMENT_STATEMENT: //e.g. x = functionCall square(2);
			{	string functionName;
				vector<float> argumentsList;
				float returnValue;
				bool isFunctionCallWellFormed,	isFunctionCallWellFinished;

				isFunctionCallWellFormed
					= getFunctionNameAndArgumentsListFromFunctionCallAssignmemt 
						(	thisInterpreterInstruction,
							localVariablesTable,
							functionName,
							argumentsList
						);

				if ( isFunctionCallWellFormed )
					isFunctionCallWellFinished
						= executeFunctionCall(functionName, argumentsList, returnValue);
				else
				{	cout << "Error! Cannot execute an ill-formed function call" << endl;
					mySyntax.displayOneInterpreterInstruction(thisInterpreterInstruction);
					return false;
				}

				if ( isFunctionCallWellFinished )
					//Store the result as the value of the variable  
					// whose name appears as the first token in the call assignment.
				{	
					if ( isDebugModeOn() )
					{
						cout << "Store the return value " << returnValue 
							 << " in "  
							 << thisInterpreterInstruction[0] << endl;
						debugBreakPoint(" ");
					}

					localVariablesTable[ thisInterpreterInstruction[0] ]
						= returnValue;
				}
				else
				{	breakPoint("Error! Not a well formed function call, aborted:");
					mySyntax.displayOneInterpreterInstruction(thisInterpreterInstruction);
					return false;
				}
			}
			break;

		case IF_HEADER_IF_STATEMENT:		 	 //e.g. if (x>1)
		case WHILE_HEADER_WHILE_STATEMENT:	 	 //e.g. while (x>1) 
		case FUNCTION_HEADER_FUNCTION_STATEMENT:	 	 //e.g. while (x>1) 
			//Do nothing
			//The getIndexNextInterpreterInstructionToExecute function
			//	will be called by the executeFunctionCall function 
			//	to evaluate the logic expression and 
			//	determine the next instruction execute
			break;

		default: //do nothing
			break;
	}

	return true;	//Keep executing next instruction

}

int Interpreter::getIndexNextInterpreterInstructionToExecute
(	int indexThisInterpreterInstruction,
	symbolTable & localVariablesTable
)
//Get the index of the next interpreter instruction to execute
{
		if ( mySyntax.mapForNextInterpreterInstruction.find(indexThisInterpreterInstruction)
			 == mySyntax.mapForNextInterpreterInstruction.end()
		   )
		   return indexThisInterpreterInstruction+1;
		//If not specified explicitly in mapForNextInterpreterInstruction,
		//	the next instruction to execute is simply the immediately following one

		interpreterInstructionCategory
			thisInterpreterInstructionCategory
			= mySyntax.categoryVectOfAllInterpreterInstructions[indexThisInterpreterInstruction];
		vector<string> thisInterpreterInstruction
			= mySyntax.vectInterpreterInstructions[indexThisInterpreterInstruction];

		switch (thisInterpreterInstructionCategory)
		{	float logicExpressionValue;

			case IF_HEADER_IF_STATEMENT:		 	 //e.g. if (x>1) 
			case WHILE_HEADER_WHILE_STATEMENT:	 	 //e.g. while (x>1)
				ExpressionEvaluator::infixEvaluator(thisInterpreterInstruction.begin()+1,
								thisInterpreterInstruction.end(),
								localVariablesTable,
								logicExpressionValue
							   );

				 if (logicExpressionValue==0.0) 
					 //if the logic condition is false
					 return  mySyntax.mapForNextInterpreterInstruction
								[indexThisInterpreterInstruction];
				 else
					 return  indexThisInterpreterInstruction+1;
				 break;
			default:
				return  mySyntax.mapForNextInterpreterInstruction
								[indexThisInterpreterInstruction];
				break;

		}
}



bool Interpreter::getCommandString
(string command, string & functionName, vector<float>& argumentsList)
{
		vector<string> commandTokenVector;
		//Call the following funtion from lexScanner.cpp to tokenize the command string
		LexicalScanner::getPerLineTokenVectFromOneStringObject
			(	command, 
				commandTokenVector
			);

		vector<tokenCategory> tokenCategoryVector;
		//Call the following funtion from lexScanner.cpp to get the token categories
		LexicalScanner::getCategoryVectorFromTokenVector
			(	commandTokenVector,
				tokenCategoryVector		
			);

		//Parse the cmmand First. The command is expected to be of the form 
		//		functionName(argument,argument,...)
		//		For example:		main()		gcd(4,8)
		//So the token vector derived from the command must have at least 3 tokens 
		//	to account for the function name and the two parantheses
		if (	commandTokenVector.size() < 3		||		
				tokenCategoryVector[0] != ID_NAME	||
				tokenCategoryVector[1]	!= LEFT_PARENTHESIS ||
				tokenCategoryVector.back()	!= RIGHT_PARENTHESIS
			)
		{	cout << "The function call command:" <<   command 
				 << " not in a right shape!" << endl << endl;
			return false;
		}

		functionName = commandTokenVector[0];
		argumentsList.clear();

		int indexToExpressionBegin,  indexToExpressionEnd;
		bool needToFindExpBegin = true;
		for (	size_t i=2; //Starting from the 3rd token
				i< commandTokenVector.size();  
				++i
			)
		{	if (needToFindExpBegin)		
			//Detect the beginning of an argument (as an expression)
				{	indexToExpressionBegin = i;
					needToFindExpBegin = false;
				}
			else	
			if	(	tokenCategoryVector[i]==COMMA	||		//A seperating comma
					i==commandTokenVector.size() -1			//The last token
				)
				//Detect the comma or the last parenthesis ) after 
				//the end of an argument (as an expression)
				{	indexToExpressionEnd = i;
					
					float argumentValue;
					bool isArgumentValid;

					//Create an enmpty table of No variables
					symbolTable emptyVariableTable; 
					
					//Evaluate the argument (as an expression)
					isArgumentValid	=	
						ExpressionEvaluator::infixEvaluator		
							(	commandTokenVector.begin()+indexToExpressionBegin, 
								commandTokenVector.begin()+indexToExpressionEnd, 
								emptyVariableTable, 
								argumentValue
							);

					if (isArgumentValid)
					{	argumentsList.push_back(argumentValue); //Store the argument
						needToFindExpBegin = true;	//Prepare to find next argument
					}
					else //Not a valid argument. Output an error message
					{	cout	<< "Cannot evaluate the argument \" "
								<< commandTokenVector[indexToExpressionBegin]
								<< "..."
								<< commandTokenVector[indexToExpressionEnd]
								<< " \" to a numerical value!" << endl;
						return false;
					}
				}

		}//End of for loop

	return true;	//All arguments  well processed
}





//Get the function name and the argument list from
//	a functionCallAssignment Interpreter Instruction.
//For example, from the following interpreter instruction
//		x = gcd(4+6, y-1)
//with variable value 1 for y,
//	this function will derives "gcd" as the function name and 
//	a vector of two values: 10 and 0 as the argument list.
bool Interpreter::getFunctionNameAndArgumentsListFromFunctionCallAssignmemt
	(	vector<string> & functionCallAssignment,
		symbolTable & localVariablesTable,
		string & functionName,
		vector<float> & argumentsList
	)
{
		vector<tokenCategory> tokenCategoryVector;
		//Call the following funtion from lexScanner.cpp to get the token categories
		LexicalScanner::getCategoryVectorFromTokenVector
			(	functionCallAssignment,
				tokenCategoryVector		
			);

		//Parse the function call assignment. It is expected to be of the form 
		//		ID_NAME = functionCall functionName(argument,argument,...);
		//		For example:		x = gcd(4,8);
		//So the token vector derived from the command must have at least 6 tokens 
		//		even if there is no argument.
		if (	functionCallAssignment.size() < 6					||		
				tokenCategoryVector[0] != ID_NAME					||
				tokenCategoryVector[1] != ASSIGNMENT_OP				||
				tokenCategoryVector[2] != ID_NAME					||
				tokenCategoryVector[3]	!= LEFT_PARENTHESIS			||
				tokenCategoryVector[tokenCategoryVector.size()-2]	
						!= RIGHT_PARENTHESIS						||
				tokenCategoryVector.back()!= SEMICOLON	
			)
		{	cout	<< "The function call assignment of:" 
					<<   functionCallAssignment[3]
					<< " not in a right shape!" 
					<< endl << endl;
			return false;
		}

		functionName = functionCallAssignment[2];
		argumentsList.clear();

		int indexToExpressionBegin,  indexToExpressionEnd;
		bool needToFindExpBegin = true;
		for (	size_t i=4; //Starting from the 5th token
				i< functionCallAssignment.size();  
				++i
			)
		{	if (needToFindExpBegin)		
			//Detect the beginning of an argument (as an expression)
				{	indexToExpressionBegin = i;
					needToFindExpBegin = false;
				}
			else	
			if	(	tokenCategoryVector[i]==COMMA	||		//A seperating comma
					i==functionCallAssignment.size()-2		//The last parenthesis
				)
				//Detect the comma or the last parenthesis ) after 
				//the end of an argument (as an expression)
				{	indexToExpressionEnd = i;
					
					float argumentValue;
					bool isArgumentValid;
					
					//Evaluate the argument (as an expression)
					isArgumentValid	=	
						ExpressionEvaluator::infixEvaluator		
							(	functionCallAssignment.begin()+indexToExpressionBegin, 
								functionCallAssignment.begin()+indexToExpressionEnd, 
								localVariablesTable, 
								argumentValue
							);

					if (isArgumentValid)
					{	argumentsList.push_back(argumentValue); //Store the argument
						needToFindExpBegin = true;	//Prepare to find next argument
					}
					else //Not a valid argument. Output an error message
					{	cout	<< "Cannot evaluate the argument \" "
								<< functionCallAssignment[indexToExpressionBegin]
								<< "..."
								<< functionCallAssignment[indexToExpressionEnd]
								<< " \" to a numerical value!" << endl;
						return false;
					}
				}

		}//End of for loop

	return true;	//All arguments  well processed
}

//Display the information in the stackOfActivatedFunctionCodeRecords
//	i.e. all the pending function calls
void Interpreter::displayStackOfActivatedFunctionCodeRecords()
{	cout << endl
		 << "Snapshot of the stack of function calls"<< endl
		 << "***************************************************" << endl << endl;

	int index = 1;
	for (	list<functionCodeRecord>::reverse_iterator 
				itr1 =stackOfActivatedFunctionCodeRecords.rbegin();
			itr1 != stackOfActivatedFunctionCodeRecords.rend();
			++itr1
		)
			{	cout << endl
					 << "*******************************************" << endl
					 << "The #" << index++ << " function call from the top of the stack: "
					 << itr1->functionName <<'(';
				if (! itr1->parametersList.empty())
				{	size_t i;
					for (i=0; i<itr1->parametersList.size()-1;++i)
						cout << itr1->parametersList[i] << '='
							 << itr1->argumentsList[i]	<< ',';

					cout << itr1->parametersList[i] << '='	//last parameter
						 << itr1->argumentsList[i];			//last argument
					cout << ')' << endl;
				}

				mySyntax.displaySymbolTable(itr1->localVariablesTable);
			}

	cout << endl << "***************************************************" << endl;
	breakPoint("End of list of all current active function calls and their codeRecords\n");
	cout << endl << endl;
}


