CTacAddr* CAstUnaryOp::ToTac(CCodeBlock *cb, CTacLabel *ltrue, CTacLabel *lfalse) { assert(cb != NULL); CTacAddr *ret = NULL; EOperation oper = GetOperation(); CAstExpression *operand = GetOperand(); CTacAddr *tOperand = NULL; if(oper == opNot) { // boolean CTacLabel *c_true = ltrue; CTacLabel *c_false = lfalse; if(!c_true || !c_false) { c_true = cb->CreateLabel(); c_false = cb->CreateLabel(); } tOperand = operand->ToTac(cb, c_false, c_true); // swap // last sequence 'not' unary op if(CAstConstant* boolConst = dynamic_cast<CAstConstant*>(operand)) { // operand is bool const if(boolConst->GetValue() == 1) // true cb->AddInstr(new CTacInstr(opGoto, c_false)); // !true = false else // false cb->AddInstr(new CTacInstr(opGoto, c_true)); // !false = true } else if(tOperand) { // if operand is id or func call, then tOperand returns not null // operand is id cb->AddInstr(new CTacInstr(opEqual, c_false, tOperand, new CTacConst(1))); cb->AddInstr(new CTacInstr(opGoto, c_true)); } if(ltrue || lfalse) { // not first of sequence 'not' unary op ret = NULL; } else { // first of sequence 'not' unary op CTacLabel *next = cb->CreateLabel(); cb->AddInstr(c_true); ret = cb->CreateTemp(operand->GetType()); cb->AddInstr(new CTacInstr(opAssign, ret, new CTacConst(1))); cb->AddInstr(new CTacInstr(opGoto, next)); cb->AddInstr(c_false); cb->AddInstr(new CTacInstr(opAssign, ret, new CTacConst(0))); cb->AddInstr(new CTacInstr(opGoto, next)); cb->AddInstr(next); } } else { // opPos || opNeg - integer tOperand = operand->ToTac(cb); ret = cb->CreateTemp(operand->GetType()); cb->AddInstr(new CTacInstr(oper, ret, tOperand)); } return ret; }
CTacAddr* CAstStatWhile::ToTac(CCodeBlock *cb, CTacLabel *next) { assert(cb != NULL && next != NULL); CAstExpression *cond = GetCondition(); CAstStatement *body = GetBody(); CTacLabel *while_cond = cb->CreateLabel("while_cond"); CTacLabel *c_true = cb->CreateLabel("while_body"); // while condition begins cb->AddInstr(while_cond); CTacAddr *tCond = cond->ToTac(cb, c_true, next); if(dynamic_cast<CAstDesignator*>(cond)) { // if cond is a single boolean cb->AddInstr(new CTacInstr(opEqual, c_true, tCond, new CTacConst(1))); cb->AddInstr(new CTacInstr(opGoto, next)); } // while body starts.. cb->AddInstr(c_true); while(body) { CTacLabel *while_next = cb->CreateLabel("while_next"); body->ToTac(cb, while_next); cb->AddInstr(while_next); body = body->GetNext(); } cb->AddInstr(new CTacInstr(opGoto, while_cond)); return NULL; }
CTacAddr* CAstStatReturn::ToTac(CCodeBlock *cb, CTacLabel *next) { assert(cb != NULL && next != NULL); CAstExpression *expr = GetExpression(); CTacAddr *tExpr = NULL; if(expr) // function case. tExpr = expr->ToTac(cb); cb->AddInstr(new CTacInstr(opReturn, NULL, tExpr)); cb->AddInstr(new CTacInstr(opGoto, next)); return NULL; }
CTacAddr* CAstStatAssign::ToTac(CCodeBlock *cb, CTacLabel *next) { assert(cb != NULL && next != NULL); CAstDesignator *lhs = GetLHS(); CAstExpression *rhs = GetRHS(); CTac *tlhs = lhs->ToTac(cb); CTacAddr *trhs = rhs->ToTac(cb); cb->AddInstr(new CTacInstr(opAssign, tlhs, trhs)); cb->AddInstr(new CTacInstr(opGoto, next)); return NULL; }
CTacAddr* CAstStatIf::ToTac(CCodeBlock *cb, CTacLabel *next) { assert(cb != NULL && next != NULL); CAstExpression *cond = GetCondition(); CAstStatement *ifBody = GetIfBody(); CAstStatement *elseBody = GetElseBody(); CTacLabel *c_true = cb->CreateLabel("if_true"); CTacLabel *c_false = cb->CreateLabel("if_false"); // starting with translate condition CTacAddr *tCond = cond->ToTac(cb, c_true, c_false); if(dynamic_cast<CAstDesignator*>(cond)) { // if cond is a single boolean cb->AddInstr(new CTacInstr(opEqual, c_true, tCond, new CTacConst(1))); cb->AddInstr(new CTacInstr(opGoto, c_false)); } // if_body starts.. cb->AddInstr(c_true); while(ifBody) { CTacLabel *if_next = cb->CreateLabel("if_next"); ifBody->ToTac(cb, if_next); cb->AddInstr(if_next); ifBody = ifBody->GetNext(); } cb->AddInstr(new CTacInstr(opGoto, next)); // if else_body exists, else_body starts.. cb->AddInstr(c_false); if(elseBody) { while(elseBody) { CTacLabel *else_next = cb->CreateLabel("else_next"); elseBody->ToTac(cb, else_next); cb->AddInstr(else_next); elseBody = elseBody->GetNext(); } cb->AddInstr(new CTacInstr(opGoto, next)); } return NULL; }
CTacAddr* CAstFunctionCall::ToTac(CCodeBlock *cb, CTacLabel *ltrue, CTacLabel *lfalse) { assert(cb != NULL); CTac *tDest = NULL; // parameters instructions for(int index = GetNArgs()-1; index >= 0; index--) { CAstExpression *arg = GetArg(index); CTacAddr *tArg = arg->ToTac(cb); CTac *tIndex = new CTacConst(index); cb->AddInstr(new CTacInstr(opParam, tIndex, tArg)); } // check if procedure or function if(GetType() != CTypeManager::Get()->GetNull()) tDest = cb->CreateTemp(GetType()); cb->AddInstr(new CTacInstr(opCall, tDest, new CTacName(GetSymbol()))); return dynamic_cast<CTacAddr*>(tDest); }
CTacAddr* CAstBinaryOp::ToTac(CCodeBlock *cb, CTacLabel *ltrue, CTacLabel *lfalse) { assert(cb != NULL); CAstExpression *left = GetLeft(); CAstExpression *right = GetRight(); CTacAddr *ret = NULL; CTacAddr *tLeft = NULL; CTacAddr *tRight = NULL; // depends on operation type, ToTac differently. EOperation oper = GetOperation(); if(IsRelOp(oper) || oper == opOr || oper == opAnd) { // related with boolean // if no given label for true & false, create them. CTacLabel *l_true = (ltrue) ? ltrue : cb->CreateLabel(); CTacLabel *l_false = (lfalse) ? lfalse : cb->CreateLabel(); CTacLabel *l_next = NULL; CTacLabel *test_next = cb->CreateLabel(); if(!ltrue || !lfalse) { // it is most out binary ops // always return type is boolean. ret = cb->CreateTemp(CTypeManager::Get()->GetBool()); // l_next is needed. l_next = cb->CreateLabel(); } switch(oper) { case opOr: tLeft = left->ToTac(cb, l_true, test_next); // left term is boolean constant. if(CAstConstant* boolConst = dynamic_cast<CAstConstant*>(left)) { if(boolConst->GetValue() == 1) // true cb->AddInstr(new CTacInstr(opGoto, l_true)); else // false cb->AddInstr(new CTacInstr(opGoto, test_next)); } //else if(dynamic_cast<CAstDesignator*>(left)) { // left term is id. else if(tLeft) { // if left term is id or func call, then tLeft is not null cb->AddInstr(new CTacInstr(opEqual, l_true, tLeft, new CTacConst(1))); cb->AddInstr(new CTacInstr(opGoto, test_next)); } cb->AddInstr(test_next); tRight = right->ToTac(cb, l_true, l_false); // right term is boolean constant. if(CAstConstant* boolConst = dynamic_cast<CAstConstant*>(right)) { if(boolConst->GetValue() == 1) // true cb->AddInstr(new CTacInstr(opGoto, l_true)); else // false cb->AddInstr(new CTacInstr(opGoto, l_false)); } //else if(dynamic_cast<CAstDesignator*>(right)) { // right term is id. else if(tRight) { // if right term is id or func call, then tRight is not null cb->AddInstr(new CTacInstr(opEqual, l_true, tRight, new CTacConst(1))); cb->AddInstr(new CTacInstr(opGoto, l_false)); } break; case opAnd: tLeft = left->ToTac(cb, test_next, l_false); // left term is boolean constant. if(CAstConstant* boolConst = dynamic_cast<CAstConstant*>(left)) { if(boolConst->GetValue() == 1) // true cb->AddInstr(new CTacInstr(opGoto, test_next)); else // false cb->AddInstr(new CTacInstr(opGoto, l_false)); } //else if(dynamic_cast<CAstDesignator*>(left)) { // left term is id. else if(tLeft) { // if left term is id or func call, then tLeft is not null cb->AddInstr(new CTacInstr(opEqual, test_next, tLeft, new CTacConst(1))); cb->AddInstr(new CTacInstr(opGoto, l_false)); } cb->AddInstr(test_next); tRight = right->ToTac(cb, l_true, l_false); // right term is boolean constant. if(CAstConstant* boolConst = dynamic_cast<CAstConstant*>(right)) { if(boolConst->GetValue() == 1) // true cb->AddInstr(new CTacInstr(opGoto, l_true)); else // false cb->AddInstr(new CTacInstr(opGoto, l_false)); } //else if(dynamic_cast<CAstDesignator*>(right)) { // right term is id. else if(tRight) { // if right term is id or func call, then tRight is not null cb->AddInstr(new CTacInstr(opEqual, l_true, tRight, new CTacConst(1))); cb->AddInstr(new CTacInstr(opGoto, l_false)); } break; // rel Ops case opEqual: case opNotEqual: case opLessThan: case opLessEqual: case opBiggerThan: case opBiggerEqual: tLeft = left->ToTac(cb, l_true, l_false); tRight = right->ToTac(cb, l_true, l_false); cb->AddInstr(new CTacInstr(oper, l_true, tLeft, tRight)); cb->AddInstr(new CTacInstr(opGoto, l_false)); break; } if(!ltrue) { // assign temp as true cb->AddInstr(l_true); cb->AddInstr(new CTacInstr(opAssign, ret, new CTacConst(1))); cb->AddInstr(new CTacInstr(opGoto, l_next)); } if(!lfalse) { // assign temp as false cb->AddInstr(l_false); cb->AddInstr(new CTacInstr(opAssign, ret, new CTacConst(0))); cb->AddInstr(new CTacInstr(opGoto, l_next)); } if(!ltrue || !lfalse) cb->AddInstr(l_next); } else { // related with integer // no need for label of true & false tLeft = left->ToTac(cb); tRight = right->ToTac(cb); ret = cb->CreateTemp(left->GetType()); // left & right same type. cb->AddInstr(new CTacInstr(oper, ret, tLeft, tRight)); } return ret; }