
#include <stdio.h>
#include <string.h>
#include "lex.h"
#include "semantics.h"

char *OPS[] = { "<", ">", "<=", ">=", "<>", "=", "+", "-", "*", "/", ":=",
				"read", "readln", "write", "writeln", "jmp", "jtrue", "jfalse",
				"jgt", "jle", "jne" };


SAS stack;								// Declaration of the semantic action stack
QTable quads;
int tempsuffix;							// Suffix used for temp vars
extern TOKEN SymTable[SYM_TABLE_SIZE];	// The symbol table
extern int iTokenCt;					// The number of tokens
extern int iNT;							// Index into table for next token



void qt_init(){
	memset(&quads, 0, sizeof(QTable));
	quads.iNQ = 1;
	tempsuffix = 0;
}//qt_init

int qt_NQ(){
	return quads.iNQ;
}//qt_NQ

void genquad(int iOperation, int iOperand1, int iOper1Offset, 
							 int iOperand2, int iOper2Offset, 
							 int iResult,   int iResultOffset){

	if(quads.iNQ > QT_LENGTH){			//Quad table is full!!!
		printf("\n *** CRITICAL ERROR: Quad table is full!\n");
		return;
	}//if

	quads.nodes[ quads.iNQ ].operation = iOperation;
	quads.nodes[ quads.iNQ ].operand1 = iOperand1;
	quads.nodes[ quads.iNQ ].oper1offset = iOper1Offset;
	quads.nodes[ quads.iNQ ].operand2 = iOperand2;
	quads.nodes[ quads.iNQ ].oper2offset = iOper2Offset;
	quads.nodes[ quads.iNQ ].result = iResult;
	quads.nodes[ quads.iNQ ].resultoffset = iResultOffset;

	quads.iNQ++;

}//genquad


//Allows a quad to be modified
void quad(int iIndex, int iWhich, int iVal){
	if((iIndex < 0) || (iIndex > QT_LENGTH) || (iIndex >= quads.iNQ))
		return;			//Do nothing if bad param

	switch(iWhich){
	case 1:
		//Do nothing if first quad is being changed....don't allow this
		break;
	case 2:
		quads.nodes[iIndex].operation = iVal;
		break;
	case 3:
		quads.nodes[iIndex].operand1 = iVal;
		break;
	case 4:
		quads.nodes[iIndex].result = iVal;
		break;
	}//switch

}//quad

//Allows the quad table to be displayed on screen.  Mainly used for debugging
void qt_debug_print(){

	int i;
	printf("\n");
	printf("   #  | Operator     | Operand1     | Operand2     | Result \n");
	printf("------+--------------+--------------+--------------+------------\n");
	for(i = 1; i < quads.iNQ; i++){
		char op[20], op1[20], op2[20], res[20];
		memset(op, 0, 20);
		memset(op1, 0, 20);
		memset(op2, 0, 20);
		memset(res, 0, 20);
		
		strcpy(op, OPS[quads.nodes[i].operation]);
		if(quads.nodes[i].operand1 != NULLOP){
			if(quads.nodes[i].oper1offset == 0)
				strcpy(op1, SymTable[quads.nodes[i].operand1].lexemeID);
			else
				sprintf(op1, "%s[%s]", SymTable[quads.nodes[i].operand1].lexemeID,
									   SymTable[quads.nodes[i].oper1offset].lexemeID);
		}
		if(quads.nodes[i].operand2 != NULLOP){
			if(quads.nodes[i].oper2offset == 0)
				strcpy(op2, SymTable[quads.nodes[i].operand2].lexemeID);
			else
				sprintf(op2, "%s[%s]", SymTable[quads.nodes[i].operand2].lexemeID,
									   SymTable[quads.nodes[i].oper2offset].lexemeID);
		}
		if(quads.nodes[i].result >= 0){
			if(quads.nodes[i].resultoffset == 0)
				strcpy(res, SymTable[quads.nodes[i].result].lexemeID);
			else
				sprintf(res, "%s[%s]", SymTable[quads.nodes[i].result].lexemeID,
										SymTable[quads.nodes[i].resultoffset].lexemeID);
		}//if
		else{
			if(quads.nodes[i].result != NULLOP)
				sprintf(res, "%d", -1*quads.nodes[i].result);
		}//else

		printf("%4d  | %11s  | %11s  | %11s  | %11s\n", i, op, op1, op2, res);

	}//for
	printf("------+--------------+--------------+--------------+------------\n");


}//qt_debug_print

int gentemp(){
	
	char buffer[20];
	
	sprintf(buffer, "t%d", tempsuffix);
	tempsuffix++;
	return addToken(buffer, TOKEN_TYPE_ID);

}//gentemp

void sas_init(){
	stack.iSize = 0;
	memset(&stack.nodes, -1, sizeof(int)*SAS_LENGTH);
}//sas_init

bool sas_push(int iVal){
	if(stack.iSize < SAS_LENGTH){
		stack.nodes[ stack.iSize] = iVal;
		stack.iSize++;
		return true;
	}//if
	else{
		printf("\n *** CRITICAL ERROR: Semantic action stack is FULL!\n");
		return false;
	}
}//sas_push

int sas_pop(){

	if(stack.iSize > 0){
		int iVal = stack.nodes[--stack.iSize];
		return iVal;
	}//if
	else
		return EMPTY_STACK;
}//sas_pop