// CodeWriter.cpp : Contains the implementation of the CodeWriter class.
//Comment the following #include statement if you are not using Visual C++
#include "StdAfx.h"

#include <stdlib.h>
#include "CodeWriter.h"
#include <sstream>

/** Constructor for the CodeWriter class.
Parameter: 
The name of the file to be written to
Result: 
Opens the file for output (writing). 
Initializes the member variables of the class
Returns: 
Nothing
*/

CodeWriter::CodeWriter(const char* output)
{
	string file(output);
	outFile.open(file.c_str(),ios::out);
	file.erase(0,file.find_last_of('\\')+1); //skip the path
    
	labelNumber = 0;	
	needHalt = 1;
}

/** Destructor for the CodeWriter class.
Parameter: 
None
Result: 
Writes the code for the infinite loop if needed (see needHalt). 
Closes the output file.
Returns: 
Nothing
*/
CodeWriter::~CodeWriter(void)
{
	if (needHalt) {
		string lbl = makeUniqueLabel();
		outFile << "(" << lbl << ")\n@" << lbl << "\n0;JEQ\n";
	}
	outFile.close();
}

/** makeUniqueLabel()
Parameter: 
None
Result: 
Uses the labelNumber member variable to create a unique label. 
Returns: 
The label as a string object.
*/
string CodeWriter::makeUniqueLabel()
{	
	stringstream ss;
	ss << (++labelNumber);
	string str = "__" + ss.str();
	return str;
}

/** makeLocalLabel()
Parameter: 
label  A string argument that is supposed to be a label unique within an input VM file or within the function that we are currently compiling. 
Result: 
Uses the label and the context (the input file's name or the function's name) to create a unique label. Remember that the function names and the file names are globally unique, thus the resulting label is globally unique. 
Returns: 
The label as a string object.
*/
string CodeWriter::makeLocalLabel(string label)
{
	string lbl;
	if (functionName.empty())
		lbl = fileName + "." + label;
	else
		lbl = functionName + "." + label;
	return lbl;
}

/** setFileName
Parameter: 
filename  A string argument, which specifies the full name of the VM input file that is about to be processed (including the path and the extension).
Result: 
Removes the path and the extension, and sets the fileName member variable to the file's name.
Returns: 
Nothing.
*/
void CodeWriter::setFileName(const char* filename)
{
	fileName = filename;
	fileName.erase(0,fileName.find_last_of(kPathSeparator)+1); //skip the path
	fileName.erase(fileName.size()-3,3);//strip the '.VM'	
}

/************************************************************
**															*
**  the functions that write ASM code start here			*
**															*
**															*
*************************************************************/

/** writePushPop
Parameter: 
cmd  The command type (either push or pop), for possible types see VMParser.h
segment A string argument, the name of the segment to/from which the data needs to be popped/pushed. 
index An integer argument, the index within the segment
Result: 
For push: Pushes the content of segment[index] onto the stack. It is a good idea to move the value to be pushed into a register first, then push the content of the register to the stack.
For pop: Pops the top of the stack into segment[index]. You may need to use a general purpose register (R13-R15) to store some temporary results.
Returns: 
Nothing.
Hint: Recall that there are 8 memory segments in the VM model, but only 5 of these exist in the assembly definition. Also, not all 8 VM segments allow to perform both pop and push on them. Chapter 7.3 of the book explains memory segment mapping.
Hint: Use pen and paper first. Figure out how to compute the address of segment[index] (except for constant). Then figure out how you move the value of segment[index] into a register (by preference D). Then figure out how to push a value from a register onto the stack. 
Hint: For pop, you already know how to compute the address of segment[index]. Store it in a temporary register (you can use R13 to R15 freely). Then read the value from the top of the stack, adjust the top of the stack, and then store the value at the location stored in the temporary register.
*/
void CodeWriter::writePushPop(CmdType cmd, string segment, int index)
{	
	//to be implemented as part of Project 6

}

/** writeArithmetic
Parameter: 
command  A string argument, the VM language menmonic of one of the nine arithmetic commands.
Result: 
Compiles the arithmetic VM command into the corresponding ASM code. Recall that the operands (one or two, depending on the command) are on the stack and the result of the operation should be placed on the stack.
The unary and the logical and arithmetic binary operators are simple to compile. 
The three comparison operators (EQ, LT and GT) do not exist in the assembly language. The corresponding assembly commands are the conditional jumps JEQ, JLT and JGT. You need to implement the VM operations using these conditional jumps. You need two labels, one for the true condition and one for the false condition and you have to put the correct result on the stack.
Returns: 
Nothing.
*/
void CodeWriter::writeArithmetic(string command)
{
	//to be implemented as part of Project 6

}


/** writeLabel
Parameter: 
label  A string argument that contains the label to be written.
Result: 
Writes a label ASM command following the ASM syntax. The label provided as argument is locally unique (within a function or within a VM file), but it could be in use in another function or in another VM file. You have to make the label globally unique by prepending some text (based on the context in which it is used right now). See makeLocalLabel .
Returns: 
Nothing.
*/
void CodeWriter::writeLabel(string label)
{
	//to be implemented as part of Project 7

}

/** writeGoto
Parameter: 
label  A string argument that contains the destination label. The same comment applies as to 'writeLabel' regarding the scope of the label.
Result: 
Writes an unconditional jump command to the label.
Returns: 
Nothing.
*/
void CodeWriter::writeGoto(string label)
{
	//to be implemented as part of Project 7

}

/** writeInit
Parameter: 
sysinit  A boolean argument, which tells whether the 'Sys.init' function should be called at the beginning of the generated ASM code.
Result: 
Writes the initialization code into the output ASM file (See Chapter 8). Calls 'Sys.init' if needed. Sets the needHalt member variable.
When writing the implementation of this function, you may not have written the implementation of WriteCall yet, but this is no problem. You just provide the function name as first parameter, and the correct number of arguments to the call, and the program will work although no code will be generated for the function call.
Returns: 
Nothing.
*/
void CodeWriter::writeInit(bool sysinit)
{
	//to be implemented as part of Project 7

}
/** writeIf
Parameter: 
label  A string argument that contains the destination label.
Result: 
Writes a conditional jump to the label. The code execution should jump if the value popped from the stack is nonzero. The same comment applies as to 'writeLabel' regarding the scope of the label.
Returns: 
Nothing.
*/
void CodeWriter::writeIf(string label)
{
	//to be implemented as part of Project 7

}

/** writeCall
Parameter: 
funcName  A string argument that contains the name of the function to be called.
numArgs   An integer argument that contains the number of arguments of the function to be called.
Result:
Writes the ASM code needed to call the function. 
Returns: 
Nothing.
Hint: Follow the instructions of the book.
Hint: You will need to create a globally unique label (see makeUniqueLabel), this is the label where code execution should continue when the called function returns (the return address).
*/
void CodeWriter::writeCall(string funcName, int numArgs)
{
	//to be implemented as part of Project 7

}

/** writeReturn
Parameter: 
Result: 
Writes the ASM code to return from a function.
Returns: 
Nothing.
Hint: Follow the instructions in the book.
Hint: Recall that you can use the general purpose registers (R13, R14, R15) to store temporary variables. 
Hint: A return statement does not imply that the function ends on this line. You should therefore not clear the function name (used to create unique labels) upon encountering this command. 
*/
void CodeWriter::writeReturn()
{	
	//to be implemented as part of Project 7

}

/** writeFunction
Parameter: 
funcName: A string parameter that specifies the function's name
numLocals: An integer parameter that specifies the number of local variables (they need to be initialized)
Result: 
Sets functionName to the function's name to keep track of the current function. Creates a label that corresponds to the function's name. 
Writes the ASM code to initialize a function, i.e., the local variables. Since the number of local variables is a parameter you will need to create a loop and initialize them one at a time.
Returns: 
Nothing.
Hint: Follow the instructions in the book.
*/
void CodeWriter::writeFunction(string funcName, int numLocals)
{
	//to be implemented as part of Project 7

}