/**
 * Function representing the <oelem> productions
 */
attr RecursiveDescentParser::oelem(ParamList* &pList) {
	attr retVal;
	retVal.type = T_ERROR;
	VariableEntry* vEntry = NULL;
	
	if(errorCondition) return retVal;
	
	if(token == TK_IDENTIFIER)
	{
#if DEBUG_PARSER
		std::cout << "<oelem> --> <var>\n";
#endif
		vEntry = var();
	}
	else if(token == TK_NUM) 
	{
#if DEBUG_PARSER
		std::cout << "<oelem> --> n\n";
#endif
		//TODO fix memory leak here vEntry is never deleted
		vEntry = new VariableEntry(T_INT, VA_SIMPLE);
		vEntry->setAddress( symTab.getNextAddress() );
		
		std::string val = token.getValue();
		int litTabIndex = litTab.insert(atoi(val.c_str()));
		iCode.threeAddressCode(vEntry->getAttr(), TAC_NUM_CONST, litTabIndex);
		
		token = scanner->getToken();
	} 
	else if(token == TK_CHAR_CONST) 
	{
#if DEBUG_PARSER
		std::cout << "<oelem> --> 'c'\n";
#endif
		//TODO fix memory leak here vEntry is never deleted
		vEntry = new VariableEntry(T_CHAR, VA_SIMPLE);
		vEntry->setAddress( symTab.getNextAddress() );
		
		std::string val = token.getValue();
		int litTabIndex = litTab.insert(val[1]);
		iCode.threeAddressCode(vEntry->getAttr(), TAC_CHAR_CONST, litTabIndex);
		
		token = scanner->getToken();
	}
	else 
	{
		errorHandler();
	}
	
	if(vEntry) {
		pList->push_back(vEntry);
		retVal = vEntry->getAttr();
	}
	
	return retVal;
}
/**
 * Function representing the <var> productions
 */
VariableEntry* RecursiveDescentParser::var() {
	VariableEntry* ve=NULL;
	
	if(errorCondition) return ve;
	
	if(token == TK_IDENTIFIER) 
	{
#if DEBUG_PARSER
		std::cout << "<var> --> i<var_prime>\n";
#endif
		TableEntry* te=NULL;
		if(!symTab.search(token, te)) 
		{			
			std::stringstream errorMsg;
			errorMsg << "Undeclared variable '" << token.getValue() << "'";
			errorHandler(errorMsg.str(), token);
		} 
		
		if(te && te->getEntryType()==TableEntry::VARIABLE) 
		{
			ve = (VariableEntry*)te;
 		}
		
		token = scanner->getToken();
		attr varP = var_prime(ve);
		
		if(ve && ve->getAttribute() == VA_ARRAY && varP.attrib == VA_SIMPLE) {
			VariableEntry* vEntry = new VariableEntry(ve->getType(), VA_SIMPLE);
			vEntry->setAddress( symTab.getNextAddress() );
			
			iCode.threeAddressCode(vEntry->getAttr(), TAC_ADDRESS_OF, ve->getAttr(), varP);
			ve = vEntry;
		}
	} 
	else 
	{
		errorHandler();
	}
	
	return ve;
}
/**
 * Function representing the <st_factor_ident> prods
 */
void RecursiveDescentParser::st_factor_ident(TableEntry* te) {
	if(errorCondition) return;
	if(token == TK_LEFT_PARENTHESES) 
	{
#if DEBUG_PARSER
		std::cout << "<st_factor_ident> --> (<o_list>);\n";
#endif
		Token leftParen = token;
		token = scanner->getToken();
		ParamList* pList = o_list();
		
		if(te) {
			if(te->getEntryType()!=TableEntry::FUNCTION) {
				std::stringstream errorMsg;
				errorMsg << "'" << te->getName() << "' is not a function";
				errorHandler(errorMsg.str(), leftParen);
			} else {
				// now makes sure the lists match
				FunctionEntry* fe = (FunctionEntry*)te;
				if(pList) matchParameters(fe, pList, leftParen);
				
				iCode.threeAddressCode(TAC_PARAM, pList);
				iCode.threeAddressCode( 
						symTab.getNextAddress(), // throw away temporary
						TAC_CALL, 
						fe->getLabel(), 
						fe->getParamCount()
					);
			}
		} else {
			std::stringstream errorMsg;
			errorMsg << "Undeclared function";
			errorHandler(errorMsg.str(), leftParen);
		}
		
		match(TK_RIGHT_PARENTHESES);
		match(TK_SEMICOLON);
	} 
	else if(token == TK_LEFT_BRACKET || 
			token == TK_ASSIGNMENT) 
	{
#if DEBUG_PARSER		
		std::cout << "<st_factor_ident> --> <var_prime>=<exp>;\n";
#endif
		VariableEntry* vEntry = (VariableEntry*)te;
		Token startToken = token;
		
		attr varAttr  = var_prime(vEntry);
		match(TK_ASSIGNMENT);
		attr expAttr = exp();
		
		if(expAttr.type != varAttr.type) {
			std::stringstream errorMsg;
			errorMsg << "Type mismatch variable '" << vEntry->getName() << "'";
			errorHandler(errorMsg.str(), startToken);
		}
		
		if(varAttr.attrib == VA_ARRAY) {
			std::stringstream errorMsg;
			errorMsg << "Assignment error, array '" << vEntry->getName() << "' must be indexed.";
			errorHandler( errorMsg.str(), startToken );
		}
		
		if(vEntry->getAttribute() == VA_ARRAY) {
			//                       array addr                           value to assign   index
			iCode.threeAddressCode(vEntry->getAttr(), TAC_ASSIGN_TO_ADDRESS_AT, expAttr, varAttr);
		} else {
			iCode.threeAddressCode(vEntry->getAttr(), TAC_ASSIGN, expAttr);
		}
		
		match(TK_SEMICOLON);
	} 
	else 
	{
		errorHandler();
	}
}