/**
 * 
 */
package dspl.backend;

import dspl.SymbolTable;
import dspl.backend.x86.X86ArithmaticInstructionrProcessor;
import dspl.backend.x86.X86BranchInstructionProcessor;
import dspl.backend.x86.X86CCallInstructionProcessor;
import dspl.backend.x86.X86LoopInstructionProcessor;
import dspl.intermediate.instructions.ArithmaticInstruction;
import dspl.intermediate.instructions.BranchInstruction;
import dspl.intermediate.instructions.CCallInstruction;
import dspl.intermediate.instructions.Instruction;
import dspl.intermediate.instructions.LoopInstruction;

/**
 * InstructionProcessor is the primary Class used to take Intermediate Instructions
 * and properly dispatch them to be converted into the appriopriate machine-specific
 * instruction set
 * @author David
 */
public class InstructionProcessor {
	/**
	 * SymbolTable for declared variables
	 */
	protected SymbolTable st;
	
	/**
	 * AssemblyfileGenerator to write the assembly instructions to
	 */
	protected AssemblyfileGenerator afg;
	
	/**
	 * The target ISA's Arithmatic Instruction processor
	 */
	protected ArithmaticInstructionProcessor aip; 
	
	/**
	 * The target ISA's Branch Instruction Processor
	 */
	protected BranchInstructionProcessor bip; 
	
	/**
	 * The target ISA's CCall Instruction Processor 
	 */
	protected CCallInstructionProcessor cip; 
	
	/**
	 * The target ISA's Loop Instruction Processor
	 */
	protected LoopInstructionProcessor lip; 
	
	/**
	 * Constructs an InstructionProcessor given the provided SymbolTable and AssemblyfileGenerator
	 * to route instructions to
	 * @param st
	 * @param afg
	 */
	public InstructionProcessor(SymbolTable st, AssemblyfileGenerator afg) {
		this.st = st; 
		this.afg = afg; 
		aip = new X86ArithmaticInstructionrProcessor(); 
		bip = new X86BranchInstructionProcessor(); 
		cip = new X86CCallInstructionProcessor(); 
		lip = new X86LoopInstructionProcessor(); 
	}
	
	public void processInstruction(Instruction inst) { 
		if (inst==null) { 
			return; 
		}
		
		switch (inst.getInstType()) { 
		case Instruction.INST_TYPE_ARITHMATIC:
			aip.processArithmaticInstructor((ArithmaticInstruction)inst, st, afg); 
			break;
		case Instruction.INST_TYPE_BRANCH:
			bip.processBranchInstruction((BranchInstruction)inst, this, st, afg); 
			break;
		case Instruction.INST_TYPE_CCALL:
			cip.processCCallInstruction((CCallInstruction)inst, this, st, afg); 
			break;
		case Instruction.INST_TYPE_FORLOOP:
			lip.ProcessLoopInstruction((LoopInstruction)inst, this, st, afg); 
			break; 
		default:
			throw new Error("Invalid unrecognized instruction type received by processInstruction: Inst Type ID = " + inst.getInstType()); 
		}
		processInstruction(inst.nextInstruction); 
		
	}	
}
