void TreeNode::GenProlog(int &jumpMain, CodeEmitter &e) const { e.emitComment("C- compiler version 1.0"); e.emitComment("Author: Cody Permann"); e.emitComment("May 13, 2004"); e.emitComment("Begin Prolog code"); e.emitRM("LD", gp, 0, 0, "load global poiniter with end of memory"); e.emitRM("LDA", fp, goff, gp, "load fp"); e.emitRM("ST", fp, 0, fp, "store old fp"); e.emitRM("LDA", ac, 1, pc, "return address in ac"); jumpMain = e.emitSkip(1); // save this address into the static variable for later e.emitRO("HALT", 0, 0, 0, "DONE!"); e.emitComment("End Prolog code"); }
void DeclarationNode::GenCode(CodeEmitter &e, bool travSib, int virtualRegister, int toff) { DeclarationNode *dPtr; // Assign virtual register to 'real' register int actualRegister = virtualRegister%MAX_EXP_REGISTERS+FIRST_REG_OFFSET; // Don't generate code for IO functions if (subKind == FuncK && name != "input" && name != "output" && name != "inputb" && name != "outputb") { // Lookup in symbol table - we'll need to set the "offset" variable dPtr = (DeclarationNode *)this; dPtr->offset = e.emitSkip(0); // save the current location for calls later // If this function is main, we need to backpatch in the jump from the prolog if (name == "main") { e.emitBackup(jumpMain); e.emitRMAbs("LDA", pc, dPtr->offset, "jump to main"); e.emitRestore(); } e.emitComment("Function " + name + " returns " + PrintType(type)); e.emitRM("ST", FIRST_REG_OFFSET, -1, fp, "store return address"); // return address is always -1 away from current frame // Load up the foff variable with the function size foff = size; // Function Body if (child[1] != NULL) { child[1]->GenCode(e, true, virtualRegister, foff); } // Add Return Statement if the function doesn't return from all branches if (!allPathsReturn) { e.emitComment("This function requires a catch all return"); e.emitRM("LDC", rt, 0, 0, "Set return value to 0"); e.emitRM("LD", actualRegister, -1, fp, "Load return address"); e.emitRM("LD", fp, 0, fp, "Adjust fp"); e.emitRM("LDA", pc, 0, actualRegister, "Return"); } else e.emitComment("This function returns from all paths, no catch all return required"); e.emitComment("End Function " + name); } if (sibling != NULL) sibling->GenCode(e, true, virtualRegister, toff); }
void StatementNode::GenCode(CodeEmitter &e, bool travSib, int virtualRegister, int toff) { int currLoc, skipLoc; // Assign virtual register to 'real' register int actualRegister = virtualRegister%MAX_EXP_REGISTERS+FIRST_REG_OFFSET; switch (subKind) { case IfK: e.emitComment("IF"); // Test Condition if (child[0] != NULL) child[0]->GenCode(e, true, virtualRegister, toff); e.emitRM("LDC", rt, 1, 0, "load constant 1"); e.emitRO("SUB", actualRegister, actualRegister, rt, "if condition check"); skipLoc = e.emitSkip(1); e.emitComment("THEN"); // Then part if (child[1] != NULL) child[1]->GenCode(e, true, virtualRegister, toff); // Else part if (child[2] != NULL) { currLoc = e.emitSkip(1); e.emitBackup(skipLoc); e.emitRMAbs("JLT", actualRegister, currLoc+1, "jump to else if false"); e.emitRestore(); skipLoc = currLoc; child[2]->GenCode(e, true, virtualRegister, toff); currLoc = e.emitSkip(0); e.emitBackup(skipLoc); e.emitRMAbs("LDA", pc, currLoc, "jump past else part"); e.emitRestore(); } else { currLoc = e.emitSkip(0); e.emitBackup(skipLoc); e.emitRMAbs("JLT", actualRegister, currLoc, "jump past then if false"); e.emitRestore(); } e.emitComment("END IF"); break; case CompK: e.emitComment("BEGIN"); if (child[1] != NULL) child[1]->GenCode(e, true, virtualRegister, toff); e.emitComment("END"); break; case WhileK: e.emitComment("WHILE"); currLoc = e.emitSkip(0); // Test Condition if (child[0] != NULL) child[0]->GenCode(e, true, virtualRegister, toff); e.emitRM("LDC", rt, 1, 0, "load constant 1"); e.emitRO("SUB", actualRegister, actualRegister, rt, "while condition check"); skipLoc = e.emitSkip(1); e.emitComment("WHILE BODY"); // While Body if (child[1] != NULL) child[1]->GenCode(e, true, virtualRegister, toff); e.emitRMAbs("LDA", pc, currLoc, "go to beginning of loop"); // Save current location to jump when While cond. is false currLoc = e.emitSkip(0); e.emitBackup(skipLoc); e.emitRMAbs("JLT", actualRegister, currLoc, "break out of loop if false"); e.emitRestore(); e.emitComment("END WHILE"); break; case ReturnK: e.emitComment("RETURN"); if (child[0] != NULL) child[0]->GenCode(e, true, virtualRegister, toff); e.emitRM("LDA", rt, 0, actualRegister, "copy result to rt register"); e.emitRM("LD", actualRegister, -1, fp, "load return address"); // Return address is one off from frame pointer e.emitRM("LD", fp, 0, fp, "adjust fp"); e.emitRM("LDA", pc, 0, actualRegister, "Return"); break; } if (sibling != NULL) { e.emitComment(NO_COMMENT); sibling->GenCode(e, true, virtualRegister, toff); } }
void ExpressionNode::GenCode(CodeEmitter &e, bool travSib, int virtualRegister, int toff) { DeclarationNode *dPtr; ExpressionNode *argPtr; int localToff, boolSkipLoc, currentLoc, currentReg; bool isUnary = true; // Assign virtual register to 'real' register int actualRegister = virtualRegister%MAX_EXP_REGISTERS+FIRST_REG_OFFSET; int nextRegister = (virtualRegister+1)%MAX_EXP_REGISTERS+FIRST_REG_OFFSET; localToff = toff; switch (subKind) { case OpK: // process left child if (child[0] != NULL) child[0]->GenCode(e, true, virtualRegister, toff); // mark location for short circuit jump if (op == "&&" || op == "||") boolSkipLoc = e.emitSkip(1); if (child[1] != NULL) { isUnary = false; // see if all of our registers are full... if (virtualRegister+1 >= MAX_EXP_REGISTERS) { // push value from "next" register e.emitRM("ST", nextRegister, toff--, fp, "dump register"); // push } else e.emitComment("Left side will remain in register"); /* // save left side localToff = toff--; e.emitRM("ST", ac, localToff, fp, "save left side"); */ // process right child child[1]->GenCode(e, true, virtualRegister+1, toff); /* // load left back into the accumulator toff = localToff; e.emitRM("LD", ac1, localToff, fp, "load left into ac1"); */ } // process operators // arithmetic operators if (op == "+") e.emitRO("ADD", actualRegister, actualRegister, nextRegister, "op +"); else if (op == "-" && !isUnary) e.emitRO("SUB", actualRegister, actualRegister, nextRegister, "op -"); else if (op == "*") e.emitRO("MUL", actualRegister, actualRegister, nextRegister, "op *"); else if (op == "/") e.emitRO("DIV", actualRegister, actualRegister, nextRegister, "op /"); else if (op == "%") { e.emitRO("DIV", rt, actualRegister, nextRegister, "begin op %"); e.emitRO("MUL", nextRegister, rt, nextRegister, ""); e.emitRO("SUB", actualRegister, actualRegister, nextRegister, "end op %"); } else if (op == "&&") { /**** Code for the non short circuit case **** e.emitRO("ADD", actualRegister, actualRegister, nextRegister, "prepare for && op"); e.emitRM("LDC", nextRegister, 2, 0, "load constant for &&"); e.emitRO("SUB", actualRegister, nextRegister, actualRegister, "compute value"); e.emitRM("JEQ", actualRegister, 2, pc, "op &&"); e.emitRM("LDC", actualRegister, 0, 0, "load false into ac"); e.emitRM("LDA", pc, 1, pc, "jump past true case"); e.emitRM("LDC", actualRegister, 1, 0, "load true into ac"); **** Code for the non short circuit case *****/ e.emitRM("JGT", nextRegister, 2, pc, "op && (right side)"); // special case: If left side of && is false then whole expression is false currentLoc = e.emitSkip(0); e.emitBackup(boolSkipLoc); e.emitRMAbs("JEQ", actualRegister, currentLoc, "Skip right child of && if left is false"); e.emitRestore(); e.emitRM("LDC", actualRegister, 0, 0, "load false into ac"); e.emitRM("LDA", pc, 1, pc, "jump past true case"); e.emitRM("LDC", actualRegister, 1, 0, "load true into ac"); } else if (op == "||") { /**** Code for the non short circuit case **** e.emitRO("ADD", actualRegister, actualRegister, nextRegister, "prepare for || op"); e.emitRM("JGT", actualRegister, 2, pc, "op ||"); e.emitRM("LDC", actualRegister, 0, 0, "load false into ac"); e.emitRM("LDA", pc, 1, pc, "jump past true case"); e.emitRM("LDC", actualRegister, 1, 0, "load true into ac"); **** Code for the non short circuit case *****/ //e.emitRM("JEQ", nextRegister, 2, pc, "op || (right side)"); /* Since the left side is short circuited the right side alone will determine whether the expression is true or false. Just make sure the RHS is int the right register */ e.emitRM("LDA", actualRegister, 0, nextRegister, "Move RHS to current accumulator"); // special case: If left side of || is true then whole expression is true currentLoc = e.emitSkip(0); e.emitBackup(boolSkipLoc); e.emitRMAbs("JGT", actualRegister, currentLoc, "Skip right child of || if left is true"); e.emitRestore(); //e.emitRM("LDC", actualRegister, 1, 0, "load true into ac"); //e.emitRM("LDA", pc, 1, pc, "jump past false case"); //e.emitRM("LDC", actualRegister, 0, 0, "load false into ac"); } else if (op == "!") { e.emitRM("JEQ", actualRegister, 2, pc, "op !"); e.emitRM("LDC", actualRegister, 0, 0, "load false into ac"); e.emitRM("LDA", pc, 1, pc, "jump past true case"); e.emitRM("LDC", actualRegister, 1, 0, "load true into ac"); } else if (op == "-" and isUnary) { e.emitRM("LDC", rt, 0, 0, "Load zero in rt for unary -"); e.emitRO("SUB", actualRegister, rt, actualRegister, "op unary -"); } else { // comparison operators e.emitRO("SUB", actualRegister, actualRegister, nextRegister, "prepare for comparison op"); if (op == "==") e.emitRM("JEQ", actualRegister, 2, pc, "op =="); else if (op == "!=") e.emitRM("JNE", actualRegister, 2, pc, "op !="); else if (op == "<") e.emitRM("JLT", actualRegister, 2, pc, "op <"); else if (op == "<=") e.emitRM("JLE", actualRegister, 2, pc, "op <="); else if (op == ">") e.emitRM("JGT", actualRegister, 2, pc, "op >"); else if (op == ">=") e.emitRM("JGE", actualRegister, 2, pc, "op >="); e.emitRM("LDC", actualRegister, 0, 0, "load false into ac"); e.emitRM("LDA", pc, 1, pc, "jump past true case"); e.emitRM("LDC", actualRegister, 1, 0, "load true into ac"); } // if we dumped a register earlier we need to restore it here if (virtualRegister+1 >= MAX_EXP_REGISTERS) { // pop value from stack back into next register e.emitRM("LD", nextRegister, ++toff, fp, "restore register"); // pop } break; case AssignK: // process RHS of assignment if (child[1] != NULL) child[1]->GenCode(e, true, virtualRegister, toff); // call function to store in LHS ((ExpressionNode *)child[0])->GenAssignLHS(e, virtualRegister, toff); break; case ConstK: e.emitRM("LDC", actualRegister, val, 0, "load constant"); break; case IdK: if (this->dPtr->isArray) { // is this array indexed? if (child[0] == NULL) { // must be a parameter if (this->dPtr->theScope == TreeNode::Parameter) e.emitRM("LD", actualRegister, this->dPtr->offset, (this->dPtr->theScope == TreeNode::Global)?gp:fp, "Load address of base of array " + this->name); else e.emitRM("LDA", actualRegister, this->dPtr->offset, (this->dPtr->theScope == TreeNode::Global)?gp:fp, "Load address of base of array " + this->name); } else { child[0]->GenCode(e, true, virtualRegister, toff); if (this->dPtr->theScope == TreeNode::Parameter) e.emitRM("LD", rt, this->dPtr->offset, (this->dPtr->theScope == TreeNode::Global)?gp:fp, "Load address of base of array " + this->name); else e.emitRM("LDA", rt, this->dPtr->offset, (this->dPtr->theScope == TreeNode::Global)?gp:fp, "Load address of base of array " + this->name); e.emitRO("SUB", actualRegister, rt, actualRegister, "index off of the base"); e.emitRM("LD", actualRegister, 0, actualRegister, "load the value"); } } else { e.emitRM("LD", actualRegister, this->dPtr->offset, (this->dPtr->theScope == TreeNode::Global)?gp:fp, "load variable " + name); } break; case CallK: // dump any used registers to temps before calling a function currentReg = actualRegister; if (currentReg > FIRST_REG_OFFSET) e.emitComment("Need to dump Registers before call"); while (currentReg > FIRST_REG_OFFSET) e.emitRM("ST", --currentReg, toff--, fp, "Save register to temporaries"); dPtr = (DeclarationNode *)symtab->lookup(name.c_str()); currentLoc = toff--; e.emitRM("ST", fp, currentLoc, fp, "Store old fp in ghost frame"); // leave room for return param --toff; // process function parameters argPtr = (ExpressionNode *)this->child[0]; // set the parameter pointer to the function declaration parameters //localToff = toff; while (argPtr != NULL) { //localToff--; //toff--; argPtr->GenCode(e, false, 0, toff); // store expression result e.emitRM("ST", FIRST_REG_OFFSET, toff-- , fp, "Save parameter"); argPtr = (ExpressionNode *)argPtr->sibling; } // prepare for jump e.emitRM("LDA", fp, currentLoc, fp, "Load address of new frame"); e.emitRM("LDA", FIRST_REG_OFFSET, 1, pc, "Put return address in ac"); e.emitRMAbs("LDA", pc, dPtr->offset, "Call " + dPtr->name); // save return value e.emitRM("LDA", actualRegister, 0, rt, "Save the result in current accumulator"); // restore temps back to registers if (currentReg < actualRegister) e.emitComment("Need to restore registers after call"); toff = currentLoc; while (currentReg < actualRegister) e.emitRM("LD", currentReg++, ++toff, fp, "Load Register from Temporaries"); // restore toff //toff = localToff; break; } if (sibling != NULL && travSib) { e.emitComment(NO_COMMENT); sibling->GenCode(e, true, 0, localToff); } }