/* * CodeGenerator.cc - Implementation of the CodeGenerator class * * Part of the assignment of the Compiler Construction course * LIACS, Leiden University */ #include "IStatement.h" #include "AssemblerCode.h" #include "MStatement.h" #include "CodeGenerator.h" #include "globals.h" #include #include #include using namespace std; bool IsGlobal(Symbol * sym); // Is the specified symbol a global variable? #define SP_ALTER(offset) fprintf(out, "\taddi\t$sp, $sp, %d\n", offset) #define OP1_NAME_C_STR(stmt) stmt->GetOperand1()->GetSymbol()->GetName().c_str() #define OP1_NAME_STR(stmt) string(SYMBOL_PREFIX) + stmt->GetOperand1()->GetSymbol()->GetName() #define OP2_NAME_C_STR(stmt) stmt->GetOperand2()->GetSymbol()->GetName().c_str() #define RESULT_NAME_C_STR(stmt) stmt->GetResult()->GetSymbol()->GetName().c_str() // Constructor CodeGenerator::CodeGenerator() : mCode(), currentFrame(mCode), rManager(currentFrame, mCode) { } // Destructor CodeGenerator::~CodeGenerator() { } // Generates a header void CodeGenerator::GenerateHeader(FILE * out) { time_t rawtime; struct tm * timeinfo; time(&rawtime); timeinfo = localtime(&rawtime); char hostname[20]; gethostname(hostname, 20); fprintf(out, "## Output generated by ./comp @ %s\n", hostname); fprintf(out, "## %s\n", asctime(timeinfo)); fprintf(out, "## Compiler Construction Course - Leiden University - LIACS\n"); fprintf(out, "## Johan IJsveld - Rick van der Zwet\n"); fprintf(out, "## BSD Licenced\n"); } // Generates the declarations for the global variables void CodeGenerator::GenerateGlobalDecls(FILE *, SymbolTable * symtab) { Scope * globalScope; Symbol * sym; mCode.AppendStatement(new MStatement(MOP_DATA, "Global data section")); mCode.AppendStatement(new MStatement(MOP_ALIGN, new MOperand(MT_INT, 4))); globalScope = symtab->GetRootScope(); // Here we iterate over all global variables in the symbol table and // generate a declaration. for (unsigned int i = 0; i < globalScope->GetNumberOfSymbols(); i++) { sym = globalScope->GetSymbol(i); if (IsGlobal(sym)) { MStatement *stmt = new MStatement(MOP_LABEL); stmt->SetLabel(string(SYMBOL_PREFIX) + sym->GetName()); mCode.AppendStatement(stmt); if (sym->GetReturnType() == RT_INT) { mCode.AppendStatement(new MStatement(MOP_WORD, new MOperand(MT_INT, 0))); } else { mCode.AppendStatement(new MStatement(MOP_FLOAT, new MOperand(MT_REAL, 0.0f))); } } } } // Takes an IntermediateCode object and emits MIPS assembly instructions void CodeGenerator::GenerateCode(FILE *out, SymbolTable * symtab, IntermediateCode * inputCode) { IStatement * stmt; // Generate a general 'stub'. mCode.AppendStatement(new MStatement(MOP_TEXT, "Code section")); mCode.AppendStatement(new MStatement(MOP_ALIGN, new MOperand(MT_INT, 4))); mCode.AppendStatement(new MStatement(MOP_GLOBL, new MOperand(MT_LABEL, "main"))); mCode.AppendStatement(new MStatement(MOP_ENT, new MOperand(MT_LABEL, "main"))); MStatement *mstmt = new MStatement(MOP_LABEL); mstmt->SetLabel("main"); mCode.AppendStatement(mstmt); mCode.AppendStatement(StackPointerChange(-4)); mCode.AppendStatement(new MStatement(MOP_JAL, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + inputCode->GetProgramName()), "Jump to program body")); mCode.AppendStatement(StackPointerChange(4)); mCode.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_V0), new MOperand(MT_REGISTER, R_ZERO), new MOperand(MT_INT, 10), "Exit system call")); mCode.AppendStatement(new MStatement(MOP_SYSCALL)); mCode.AppendStatement(new MStatement(MOP_END, new MOperand(MT_LABEL, "main"))); // Here we step through the intermediate code and output assembly instructions for (unsigned int i = 0; i < inputCode->GetStatementCount(); i++) { stmt = inputCode->GetStatement(i); switch (stmt->GetOperator()) { /* Subprogram entry operand1 should refer to the corresponding Symbol_Subprogram object */ case IOP_SUBPROG: // [1--] Subprogram { // The start of a subprogram: analyze it, and generate the prologue. currentFrame.AnalyzeSubprogram(symtab, stmt->GetOperand1()->GetSymbol()); currentFrame.GeneratePrologue(out); break; } /* Subprogram return operand1 should contain the value that has to be returned */ case IOP_RETURN: // [---] Procedure return { // The end of a subprogram: // write back all registers rManager.SpillAll(); // generate the epilogue currentFrame.GenerateEpilogue(out); break; } case IOP_RETURN_I: // [1--] Integer function return { // The end of a subprogram: // write back all registers rManager.SpillAll(); // put result in $v0 if (stmt->GetOperand1()->GetOperandType() == OT_INT) { mCode.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_V0), new MOperand(MT_REGISTER, R_ZERO), new MOperand(MT_INT, stmt->GetOperand1()->GetIntValue()), "Store constant integer return value")); } else { MRegisterType result_reg = rManager.GetIntRegister(stmt->GetOperand1()->GetSymbol()); mCode.AppendStatement(new MStatement(MOP_MOVE, new MOperand(MT_REGISTER, R_V0), new MOperand(MT_REGISTER, result_reg), "Store integer return value")); } // generate the epilogue currentFrame.GenerateEpilogue(out); break; } case IOP_RETURN_R: // [1--] Real function return { // The end of a subprogram: // write back all registers rManager.SpillAll(); // put result in $f0 if (stmt->GetOperand1()->GetOperandType() == OT_REAL) { mCode.AppendStatement(new MStatement(MOP_LI_S, new MOperand(MT_REGISTER, R_F0), new MOperand(MT_REAL, stmt->GetOperand1()->GetRealValue()), "Store constant real return value")); } else if (stmt->GetOperand1()->GetOperandType() == OT_REAL) { // XXX: is this needed? mCode.AppendStatement(new MStatement(MOP_LI_S, new MOperand(MT_REGISTER, R_F0), new MOperand(MT_INT, stmt->GetOperand1()->GetRealValue()), "Store real (casted from int) return value")); } else { MRegisterType result_reg = rManager.GetFloatRegister(stmt->GetOperand1()->GetSymbol()); mCode.AppendStatement(new MStatement(MOP_MOV_S, new MOperand(MT_REGISTER, R_F0), new MOperand(MT_REGISTER, result_reg), "Store real return value")); } // generate the epilogue currentFrame.GenerateEpilogue(out); break; } /* Meta */ case IOP_UNKNOWN: // [---] (yet) Unknown operation { assert(0); // can't happen break; } /* Parameter passing (caller side) operand1 actual parameter value or Symbol object */ case IOP_PARAM_I: // [1--] Integer parameter { if (stmt->GetOperand1()->GetOperandType() == OT_INT) { mCode.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_V1), new MOperand(MT_REGISTER, R_ZERO), new MOperand(MT_INT, stmt->GetOperand1()->GetIntValue()), "Push constant integer parameter")); } else { // find/associate operand symbol to a register MRegisterType operand_reg = rManager.GetIntRegister(stmt->GetOperand1()->GetSymbol()); mCode.AppendStatement(new MStatement(MOP_MOVE, new MOperand(MT_REGISTER, R_V1), new MOperand(MT_REGISTER, operand_reg), "Push integer parameter")); } mCode.AppendStatement(new MStatement(MOP_SW, new MOperand(MT_REGISTER, R_V1), new MOperand(MT_OFFSET, R_SP, 0))); mCode.AppendStatement(StackPointerChange(-4)); break; } case IOP_PARAM_R: // [1--] Real parameter { if (stmt->GetOperand1()->GetOperandType() == OT_REAL) { mCode.AppendStatement(new MStatement(MOP_LI_S, new MOperand(MT_REGISTER, R_F0), new MOperand(MT_REAL, stmt->GetOperand1()->GetRealValue()), "Push constant real parameter")); } else { // find/associate operand symbol to a register MRegisterType operand_reg = rManager.GetFloatRegister(stmt->GetOperand1()->GetSymbol()); mCode.AppendStatement(new MStatement(MOP_MOV_S, new MOperand(MT_REGISTER, R_F0), new MOperand(MT_REGISTER, operand_reg), "Push real parameter")); } mCode.AppendStatement(new MStatement(MOP_S_S, new MOperand(MT_REGISTER, R_F0), new MOperand(MT_OFFSET, R_SP, 0))); mCode.AppendStatement(StackPointerChange(-4)); break; } /* Subprogram call operand1 should refer to the corresponding Symbol object result receives the result of a function call */ case IOP_PROCCALL: // [1--] Procedure call { /* making a procedure call so write back all registers */ rManager.SpillAll(); /* make procedure call */ mCode.AppendStatement(new MStatement(MOP_JAL, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + OP1_NAME_C_STR(stmt)))); break; } case IOP_FUNCCALL: // [1-r] Function call { /* making a function call so write back all registers */ rManager.SpillAll(); /* Function call requires a call and then storage of returned data */ mCode.AppendStatement(new MStatement(MOP_JAL, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + OP1_NAME_C_STR(stmt)))); /* find/associate a register and put the result in there */ Symbol *result_symbol = stmt->GetResult()->GetSymbol(); if (result_symbol->GetReturnType() == RT_INT) { MRegisterType result_reg = rManager.GetIntRegister(result_symbol); mCode.AppendStatement(new MStatement(MOP_MOVE, new MOperand(MT_REGISTER, result_reg), new MOperand(MT_REGISTER, R_V0), "Store integer function result")); } else { MRegisterType result_reg = rManager.GetFloatRegister(result_symbol); mCode.AppendStatement(new MStatement(MOP_MOV_S, new MOperand(MT_REGISTER, result_reg), new MOperand(MT_REGISTER, R_F0), "Store real function result")); } break; } /* Label operand1 should refer to the corresponding Symbol object */ case IOP_LABEL: // [1--] Label { MStatement *mstmt = new MStatement(MOP_LABEL); mstmt->SetLabel(OP1_NAME_C_STR(stmt)); mCode.AppendStatement(mstmt); break; } /* Goto operand1 should refer to the corresponding Symbol object; note that the Symbol pointed to should be of type ST_LABEL */ case IOP_GOTO: // [1--] Goto a label { /* changing control flow so write back all registers */ rManager.SpillAll(); mCode.AppendStatement(new MStatement(MOP_J, new MOperand(MT_LABEL, OP1_NAME_C_STR(stmt)))); break; } /* Variable assignment (copy value) operand1 the source operand result the destination operand (pointer to a Symbol object) */ case IOP_ASSIGN_I: // [1-r] Integer assignment { // find/associate result symbol to a register MRegisterType result_reg = rManager.GetIntRegister(stmt->GetResult()->GetSymbol()); if (stmt->GetOperand1()->GetOperandType() == OT_INT) { mCode.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, result_reg), new MOperand(MT_REGISTER, R_ZERO), new MOperand(MT_INT, stmt->GetOperand1()->GetIntValue()), "Assign constant integer")); } else { // find/associate operand symbol to a register MRegisterType operand_reg = rManager.GetIntRegister(stmt->GetOperand1()->GetSymbol()); mCode.AppendStatement(new MStatement(MOP_MOVE, new MOperand(MT_REGISTER, result_reg), new MOperand(MT_REGISTER, operand_reg), "Assign integer")); } break; } case IOP_ASSIGN_R: // [1-r] Real assignment { // find/associate result symbol to a register MRegisterType result_reg = rManager.GetFloatRegister(stmt->GetResult()->GetSymbol()); if (stmt->GetOperand1()->GetOperandType() == OT_REAL) { mCode.AppendStatement(new MStatement(MOP_LI_S, new MOperand(MT_REGISTER, result_reg), new MOperand(MT_REAL, stmt->GetOperand1()->GetRealValue()), "Assign constant real")); } else { // find/associate operand symbol to a register MRegisterType operand_reg = rManager.GetFloatRegister(stmt->GetOperand1()->GetSymbol()); mCode.AppendStatement(new MStatement(MOP_MOV_S, new MOperand(MT_REGISTER, result_reg), new MOperand(MT_REGISTER, operand_reg), "Assign real")); } break; } /* Branching operand1 the first source operand operand2 the second source operand result should refer to the target Symbol object; note that the Symbol pointed to must be of type ST_LABEL */ case IOP_BEQ_I: // [12r] = operator for integers { mCode.AppendStatement(BranchInstruction(MOP_BEQ, stmt)); break; } case IOP_BLT_I: // [12r] < operator for integers { mCode.AppendStatement(BranchInstruction(MOP_BLT, stmt)); break; } case IOP_BGT_I: // [12r] > operator for integers { mCode.AppendStatement(BranchInstruction(MOP_BGT, stmt)); break; } case IOP_BLE_I: // [12r] <= operator for integers { mCode.AppendStatement(BranchInstruction(MOP_BLE, stmt)); break; } case IOP_BGE_I: // [12r] >= operator for integers { mCode.AppendStatement(BranchInstruction(MOP_BGE, stmt)); break; } case IOP_BNE_I: // [12r] <> operator for integers { mCode.AppendStatement(BranchInstruction(MOP_BNE, stmt)); break; } case IOP_BEQ_R: // [12r] = operator for reals { mCode.AppendStatement(BranchInstructionReal(MOP_C_EQ_S, stmt)); mCode.AppendStatement(new MStatement(MOP_BCZT, new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt)))); break; } case IOP_BLT_R: // [12r] < operator for reals { mCode.AppendStatement(BranchInstructionReal(MOP_C_LT_S, stmt)); mCode.AppendStatement(new MStatement(MOP_BCZT, new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt)))); break; } case IOP_BGT_R: // [12r] > operator for reals { /* Use reverse style not (<=) */ mCode.AppendStatement(BranchInstructionReal(MOP_C_LT_S, stmt, true)); mCode.AppendStatement(new MStatement(MOP_BCZT, new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt)))); break; } case IOP_BLE_R: // [12r] <= operator for reals { mCode.AppendStatement(BranchInstructionReal(MOP_C_LE_S, stmt)); mCode.AppendStatement(new MStatement(MOP_BCZT, new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt)))); break; } case IOP_BGE_R: // [12r] >= operator for reals { mCode.AppendStatement(BranchInstructionReal(MOP_C_LE_S, stmt, true)); mCode.AppendStatement(new MStatement(MOP_BCZF, new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt)))); break; } case IOP_BNE_R: // [12r] <> operator for reals { mCode.AppendStatement(BranchInstructionReal(MOP_C_EQ_S, stmt)); mCode.AppendStatement(new MStatement(MOP_BCZF, new MOperand(MT_LABEL, RESULT_NAME_C_STR(stmt)))); break; } /* Binary arithmetic operators operand1 the first source operand operand2 the second source operand result the destination operand (refers to a Symbol object) */ case IOP_ADD_I: // [12r] Integer addition { mCode.AppendStatement(BinaryArithmetic(MOP_ADD, stmt, "Add integers")); break; } case IOP_ADD_R: // [12r] Real addition { mCode.AppendStatement(BinaryArithmetic(MOP_ADD_S, stmt, "Add reals")); break; } case IOP_SUB_I: // [12r] Integer substraction { mCode.AppendStatement(BinaryArithmetic(MOP_SUB, stmt, "Subtract integer")); break; } case IOP_SUB_R: // [12r] Real substraction { mCode.AppendStatement(BinaryArithmetic(MOP_SUB_S, stmt, "Subtract reals")); break; } case IOP_MUL_I: // [12r] Integer multiplication { mCode.AppendStatement(BinaryArithmetic(MOP_MUL, stmt, "Multiply integers")); break; } case IOP_MUL_R: // [12r] Real multiplication { mCode.AppendStatement(BinaryArithmetic(MOP_MUL_S, stmt, "Multiply reals")); break; } case IOP_DIV_I: // [12r] Integer division { mCode.AppendStatement(BinaryArithmetic(MOP_DIV, stmt, "Divide integers")); break; } case IOP_DIV_R: // [12r] Real division { mCode.AppendStatement(BinaryArithmetic(MOP_DIV_S, stmt, "Divide reals")); break; } case IOP_MOD: // [12r] Modulo { mCode.AppendStatement(BinaryArithmetic(MOP_REM, stmt, "Remainder")); break; } case IOP_AND: // [12r] AND operation { mCode.AppendStatement(BinaryArithmetic(MOP_AND, stmt, "Bitwise and")); break; } case IOP_OR: // [12r] OR operation { mCode.AppendStatement(BinaryArithmetic(MOP_OR, stmt, "Bitwise or")); break; } /* Unary arithmetic operators operand1 the source operand result the destination operand (refers to a Symbol object) */ case IOP_NOT: // [1-r] NOT operation { mCode.AppendStatement(UnaryArithmetic(MOP_NOT, stmt, "Bitwise not")); break; } case IOP_UNARY_MINUS_I: // [1-r] Unary integer minus { mCode.AppendStatement(UnaryArithmetic(MOP_NEG, stmt, "Negate integer")); break; } case IOP_UNARY_MINUS_R: // [1-r] Unary real minus { mCode.AppendStatement(UnaryArithmetic(MOP_NEG_S, stmt, "Negate real")); break; } /* Coercion operand1 the source operand result the destination operand (refers to a Symbol object) */ case IOP_INT_TO_REAL: // [1-r] Int to Real coercion { MRegisterType dest_reg = rManager.GetFloatRegister(stmt->GetResult()->GetSymbol()); if (stmt->GetOperand1()->GetOperandType() == OT_INT) { // just add constant float value = stmt->GetOperand1()->GetIntValue(); mCode.AppendStatement(new MStatement(MOP_LI_S, new MOperand(MT_REGISTER, dest_reg), new MOperand(MT_REAL, value), "Coerce constant from int to real")); } else { // load integer into register and load it into floating point register MRegisterType source_reg = rManager.GetIntRegister(stmt->GetOperand1()->GetSymbol()); mCode.AppendStatement(new MStatement(MOP_MTC1, new MOperand(MT_REGISTER, source_reg), new MOperand(MT_REGISTER, dest_reg), "Coerce from int to real")); // convert integer to float mCode.AppendStatement(new MStatement(MOP_CVT_S_W, new MOperand(MT_REGISTER, dest_reg), new MOperand(MT_REGISTER, dest_reg))); } break; } default: fprintf(stderr, "[CodeGenerator::GenerateCode()] Unhandled intermediate operator '%s'\n", IOperatorToString(stmt->GetOperator()) ); } } } MOperand * CodeGenerator::IOperand2MOperand(IOperand * opnd) { MOperand *retVal; MRegisterType freeRegister; switch (opnd->GetOperandType()) { case OT_SYMBOL: { MRegisterType tmpReg = rManager.GetRegister(opnd->GetSymbol()); retVal = new MOperand(MT_REGISTER, tmpReg); break; } case OT_INT: { freeRegister = rManager.GetTempRegister(); mCode.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, freeRegister), new MOperand(MT_REGISTER, R_ZERO), new MOperand(MT_INT, opnd->GetIntValue()))); retVal = new MOperand(MT_REGISTER, freeRegister); break; } case OT_REAL: { freeRegister = rManager.GetTempRegister(); mCode.AppendStatement(new MStatement(MOP_LI_S, new MOperand(MT_REGISTER, freeRegister), new MOperand(MT_REAL, opnd->GetRealValue()))); retVal = new MOperand(MT_REGISTER, freeRegister); break; } default: /* XXX: Should not happen */ break; } return (retVal); } // Generates a trailer /* Stack Pointer template */ MStatement * CodeGenerator::StackPointerChange(int offset, const char * comment) { MOperand *mop1 = new MOperand(MT_REGISTER, R_SP); MOperand *mop2 = new MOperand(MT_REGISTER, R_SP); MOperand *mop3 = new MOperand(MT_INT, offset); return (new MStatement(MOP_ADDI, mop1, mop2, mop3, comment)); } /* Unary Artithmetic template */ MStatement * CodeGenerator::UnaryArithmetic(MOperator opcode, IStatement *stmt, const char * comment) { MOperand *mop1 = IOperand2MOperand(stmt->GetResult()); MOperand *mop2 = IOperand2MOperand(stmt->GetOperand1()); return (new MStatement(opcode, mop1, mop2, comment)); } /* Binary Artithmetic template */ MStatement * CodeGenerator::BinaryArithmetic(MOperator opcode, IStatement *stmt, const char * comment) { MOperand *mop1 = IOperand2MOperand(stmt->GetResult()); MOperand *mop2 = IOperand2MOperand(stmt->GetOperand1()); MOperand *mop3 = IOperand2MOperand(stmt->GetOperand2()); return (new MStatement(opcode, mop1, mop2, mop3, comment)); } /* Branch Instruction with Int values template */ MStatement * CodeGenerator::BranchInstruction(MOperator opcode, IStatement *stmt, bool swap, const char * comment) { MOperand *mop1 = IOperand2MOperand(stmt->GetOperand1()); MOperand *mop2 = IOperand2MOperand(stmt->GetOperand2()); MOperand *mop3 = new MOperand(MT_LABEL, stmt->GetResult()->GetSymbol()->GetName()); /* changing control flow so write back all registers */ rManager.SpillAll(); if (swap) return (new MStatement(opcode, mop1, mop2, mop3, comment)); else return (new MStatement(opcode, mop2, mop1, mop3, comment)); } /* Branch Instruction with Real values temlate */ MStatement * CodeGenerator::BranchInstructionReal(MOperator opcode, IStatement *stmt, bool swap, const char * comment) { MOperand *mop1 = IOperand2MOperand(stmt->GetOperand1()); MOperand *mop2 = IOperand2MOperand(stmt->GetOperand2()); if (swap) return (new MStatement(opcode, mop1, mop2, comment)); else return (new MStatement(opcode, mop2, mop1, comment)); } void CodeGenerator::Dump(FILE * out) { mCode.Dump(out); fprintf(out, "\n"); } void CodeGenerator::GenerateTrailer(FILE *) { /* readinteger: syscall code 5, integer in $v0 * General idea: init, set syscall value, call syscall, save value */ { mCode.AppendStatement(new MStatement(MOP_ENT, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("readinteger")), "Start of builtin functions and procedures")); MStatement *stmt = new MStatement(MOP_LABEL); stmt->SetLabel(string(SYMBOL_PREFIX) + string("readinteger")); mCode.AppendStatement(stmt); mCode.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_V0), new MOperand(MT_REGISTER, R_ZERO), new MOperand(MT_INT, 5))); mCode.AppendStatement(new MStatement(MOP_SYSCALL)); mCode.AppendStatement(new MStatement(MOP_JR, new MOperand(MT_REGISTER, R_RA))); mCode.AppendStatement(new MStatement(MOP_END, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("readinteger")))); } /* writeinteger: syscall code 1, integer in $a0 * General idea: init, set syscall value, ,set value, call syscall */ { mCode.AppendStatement(new MStatement(MOP_ENT, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("writeinteger")))); MStatement *stmt = new MStatement(MOP_LABEL); stmt->SetLabel(string(SYMBOL_PREFIX) + string("writeinteger")); mCode.AppendStatement(stmt); mCode.AppendStatement(new MStatement(MOP_LW, new MOperand(MT_REGISTER, R_A0), new MOperand(MT_OFFSET, R_SP, 4))); mCode.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_V0), new MOperand(MT_REGISTER, R_ZERO), new MOperand(MT_INT, 1))); mCode.AppendStatement(new MStatement(MOP_SYSCALL)); mCode.AppendStatement(StackPointerChange(4)); mCode.AppendStatement(new MStatement(MOP_JR, new MOperand(MT_REGISTER, R_RA))); mCode.AppendStatement(new MStatement(MOP_END, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("writeinteger")))); } /* readreal: syscall code 6, float in $f0 * General idea: init, set syscall value, call syscall, save value */ { mCode.AppendStatement(new MStatement(MOP_ENT, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("readreal")))); MStatement *stmt = new MStatement(MOP_LABEL); stmt->SetLabel(string(SYMBOL_PREFIX) + string("readreal")); mCode.AppendStatement(stmt); mCode.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_V0), new MOperand(MT_REGISTER, R_ZERO), new MOperand(MT_INT, 6))); mCode.AppendStatement(new MStatement(MOP_SYSCALL)); mCode.AppendStatement(new MStatement(MOP_JR, new MOperand(MT_REGISTER, R_RA))); mCode.AppendStatement(new MStatement(MOP_END, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("readreal")))); } /* writereal: syscall code 2, float in $f12 * General idea: init, set syscall value, ,set value, call syscall */ { mCode.AppendStatement(new MStatement(MOP_ENT, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("writereal")))); MStatement *stmt = new MStatement(MOP_LABEL); stmt->SetLabel(string(SYMBOL_PREFIX) + string("writereal")); mCode.AppendStatement(stmt); mCode.AppendStatement(new MStatement(MOP_L_S, new MOperand(MT_REGISTER, R_F12), new MOperand(MT_OFFSET, R_SP, 4))); mCode.AppendStatement(new MStatement(MOP_ADDI, new MOperand(MT_REGISTER, R_V0), new MOperand(MT_REGISTER, R_ZERO), new MOperand(MT_INT, 2))); mCode.AppendStatement(new MStatement(MOP_SYSCALL)); mCode.AppendStatement(StackPointerChange(4)); mCode.AppendStatement(new MStatement(MOP_JR, new MOperand(MT_REGISTER, R_RA))); mCode.AppendStatement(new MStatement(MOP_END, new MOperand(MT_LABEL, string(SYMBOL_PREFIX) + string("writereal")))); } }