Example #1
0
CAstStatCall* CParser::subroutineCall(CAstScope *s, CToken ident) {
  //
  // subroutineCall ::= ident "(" [ expression {"," expression} ] ")".
  //

  CToken t;
  Consume(tLBrak);
  CSymtab *symtab = s->GetSymbolTable();
  CAstFunctionCall *call = NULL;

  // Check undefined procedure/function call.
  if(symtab->FindSymbol(ident.GetValue(), sLocal) == NULL && symtab->FindSymbol(ident.GetValue(), sGlobal) != NULL) {
    // Check if symbol is procedure.
    if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(ident.GetValue(), sGlobal)) == NULL)
      SetError(ident, "invalid procedure/function identifier.");
    
    call = new CAstFunctionCall(ident, dynamic_cast<const CSymProc *>(symtab->FindSymbol(ident.GetValue(), sGlobal)));
  }
  else if(symtab->FindSymbol(ident.GetValue(), sLocal) != NULL) {
    // Check if symbol is procedure.
    if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(ident.GetValue(), sLocal)) == NULL)
        SetError(ident, "invalid procedure/function identifier.");
    
    call = new CAstFunctionCall(ident, dynamic_cast<const CSymProc *>(symtab->FindSymbol(ident.GetValue(), sLocal)));
  }
  else
    SetError(ident, "undefined identifier.");
  
  // Add expressions.
  if(isExpr(_scanner->Peek())) {
    CAstExpression *expr = expression(s);
    assert(expr != NULL);

    // Arrays are addressed.
    if(expr->GetType()->IsArray())
      expr = new CAstSpecialOp(expr->GetToken(), opAddress, expr, NULL);

    call->AddArg(expr);

    while(_scanner->Peek().GetType() == tComma) {
      Consume(tComma);
      expr = expression(s);
      assert(expr != NULL);

      // Arrays are addressed.
      if(expr->GetType()->IsArray())
        expr = new CAstSpecialOp(expr->GetToken(), opAddress, expr, NULL);

      call->AddArg(expr);
    }
  }
  
  Consume(tRBrak);

  return new CAstStatCall(ident, call);
}
Example #2
0
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;
}
Example #3
0
bool CAstBinaryOp::TypeCheck(CToken *t, string *msg) const
{
  EOperation oper = GetOperation();
  CAstExpression *left = GetLeft();
  CAstExpression *right = GetRight();

  if(!left->TypeCheck(t, msg)) return false;
  if(!right->TypeCheck(t, msg)) return false;

  switch(oper) {
    case opAdd:
    case opSub:
    case opMul:
    case opDiv:
      if(left->GetType() != CTypeManager::Get()->GetInt() ||
        right->GetType() != CTypeManager::Get()->GetInt()) {
        if (t != NULL) *t = GetToken();
        if (msg != NULL) *msg = "Operand types should be integer for '+','-','*',or '/'.";
        return false;
      }
      break;
    case opAnd:
    case opOr:
      if(left->GetType() != CTypeManager::Get()->GetBool() ||
        right->GetType() != CTypeManager::Get()->GetBool()) {
        if (t != NULL) *t = GetToken();
        if (msg != NULL) *msg = "Operand types should be boolean for '&&',or '||'.";
        return false;
      }
      break;
    case opEqual:
    case opNotEqual:
      if(left->GetType() != right->GetType()) {
        if (t != NULL) *t = GetToken();
        if (msg != NULL) *msg = "Operand types should be same for '=',or '#'.";
        return false;
      } else if(left->GetType() == CTypeManager::Get()->GetNull()) {
        // left and right has same type, so we only check left type
        if (t != NULL) *t = GetToken();
        if (msg != NULL) *msg = "Operand types should not be NULL.";
        return false;
      }
      break;
    case opLessThan:
    case opLessEqual:
    case opBiggerThan:
    case opBiggerEqual:
      if(left->GetType() != CTypeManager::Get()->GetInt() ||
        right->GetType() != CTypeManager::Get()->GetInt()) {
        if (t != NULL) *t = GetToken();
        if (msg != NULL) *msg = "Operand types should be integer for '<','<=','>',or '>='.";
        return false;
      }
      break;
  }
  
  return true;
}
Example #4
0
CAstExpression* CParser::addressExpression(CAstScope* s)
{
  //
  // addressExpression ::= "&" expression
  // implicit type casting: array to pointer
  //
  CToken t = _scanner->Peek();
  CAstExpression *e = expression(s);

  if (!e->GetType())
    SetError(t, "NULL type");
  else if (e->GetType()->IsArray())
    return new CAstSpecialOp(t, opAddress, e, NULL);

  return e;
}
Example #5
0
bool CAstArrayDesignator::TypeCheck(CToken *t, string *msg) const
{
  bool result = true;
  assert(_done);

  if(!GetType()) { // if GetType is NULL then it is an invalid array expression
    if(t != NULL) *t = GetToken();
    if(msg != NULL) *msg = "invalid array expression.";
    return false;
  }

  int i;
  for(i = 0; i < GetNIndices(); i++) {
    CAstExpression *e = GetIndex(i);
    if(!e->TypeCheck(t, msg)) return false; // Do TypeCheck on indexing expression

    if(!e->GetType()->IsInt()) { // The indexing expression should be Int type
      if(t != NULL) *t = e->GetToken();
      if(msg != NULL) *msg = "invalid array index expression.";
      return false;
    }
  }

  return result;
}
Example #6
0
bool CAstStatIf::TypeCheck(CToken *t, string *msg) const
{
  CAstExpression *cond = GetCondition();
  bool result = true;
  
  if (!cond->TypeCheck(t, msg)) return false;
  if (cond->GetType() != CTypeManager::Get()->GetBool()) {
    if (t != NULL) *t = cond->GetToken();
    if (msg != NULL) *msg = "boolean expression expected.";
    return false;
  }

  try {
    CAstStatement *ifBody = GetIfBody();
    CAstStatement *elseBody = GetElseBody();
    
    while (result && (ifBody != NULL)) {
      result = ifBody->TypeCheck(t, msg);
      ifBody = ifBody->GetNext();
    }
    
    while (result && (elseBody != NULL)) {
      result = elseBody->TypeCheck(t, msg);
      elseBody = elseBody->GetNext();
    }
  } catch (...) {
    result = false;
  }
  
  return result;
}
Example #7
0
bool CAstStatReturn::TypeCheck(CToken *t, string *msg) const
{
  const CType *st = GetScope()->GetType();
  CAstExpression *e = GetExpression();
  
  if (st->Match(CTypeManager::Get()->GetNull())) {
    if (e != NULL) {
      if (t != NULL) *t = e->GetToken();
      if (msg != NULL) *msg = "superfluous expression after return.";
      return false;
    }
  } else {
    if (e == NULL) {
      if (t != NULL) *t = GetToken();
      if (msg != NULL) *msg = "expression expected after return.";
      return false;
    }

    if (!e->TypeCheck(t, msg)) return false;

    if (!st->Match(e->GetType())) {
      if (t != NULL) *t = e->GetToken();
      if (msg != NULL) *msg = "return type mismatch.";
      return false;
    }
  }

  return true;
}
Example #8
0
bool CAstFunctionCall::TypeCheck(CToken *t, string *msg) const
{
  const CSymProc *symbol = GetSymbol();
  
  // check the number of procedure/function arguments.
  if (GetNArgs() != symbol->GetNParams()) {
    if (t != NULL) *t = GetToken();
    if (msg != NULL) *msg = "the number of arguments mismatch.";
    return false;
  }

  // first, type check for expression of arguments.
  // then, check the types of procedure/function arguments.
  // in this project, arguments type is only integer.
  for (int i = 0; i < GetNArgs(); i++) {
    CAstExpression *arg = GetArg(i);
    if (!arg->TypeCheck(t, msg)) return false;

    if (arg->GetType() != symbol->GetParam(i)->GetDataType()) {
      if (t != NULL) *t = arg->GetToken();
      if (msg != NULL) *msg = "the type of arguments mismatch.";
      return false;
    }
  }

  return true;
}
Example #9
0
bool CAstUnaryOp::TypeCheck(CToken *t, string *msg) const
{
  CAstExpression *e = GetOperand();
  
  if (!e->TypeCheck(t, msg)) return false;
  
  if( ((GetOperation() == opPos || GetOperation() == opNeg) && 
      (e->GetType() != CTypeManager::Get()->GetInt())) ||
      ((GetOperation() == opNot) && 
      (e->GetType() != CTypeManager::Get()->GetBool())) ) {
    if (t != NULL) *t = GetToken();
    if (msg != NULL) *msg = "unary operation type mismatch.";
    return false;
  }
  
  return true;
}
Example #10
0
const CType* CAstUnaryOp::GetType(void) const
{
  CTypeManager *tm = CTypeManager::Get();
  EOperation oper = GetOperation();
  CAstExpression *e = GetOperand();

  if(e->GetType() == NULL)
    return NULL;

  if(oper == opNeg || oper == opPos) { //case '+' || '-'
    if(e->GetType()->IsInt())
      return tm->GetInt();
    else return NULL;
  }
  else { // case '!'
    if(e->GetType()->IsBoolean())
      return tm->GetBool();
  
    else return NULL;
  }
}
Example #11
0
bool CAstStatAssign::TypeCheck(CToken *t, string *msg) const
{
  CAstDesignator *id = GetLHS();
  CAstExpression *e = GetRHS();
  
  if (!id->TypeCheck(t, msg)) return false;
  if (!e->TypeCheck(t, msg)) return false;

  if (!id->GetType()->Match(e->GetType())) {
    if (t != NULL) *t = e->GetToken();
    if (msg != NULL) *msg = "assignment type mismatch.";
    return false;
  }

  return true;
}
Example #12
0
CAstExpression* CParser::factor(CAstScope *s) {
  //
  // factor ::= qualident | number | boolean | char | string | "(" expression ")" | subroutineCall | "!" factor.
  // FIRST(factor) = { tIdent, tNumber, tTrue, tFalse, tCharacter, tString, tLBrak, tEMark }.
  //
  
  CToken t;
  EToken tt = _scanner->Peek().GetType();
  CTypeManager *tm = CTypeManager::Get();
  CAstExpression *n = NULL;
  CSymtab *symtab = s->GetSymbolTable();

  switch(tt) {
    case tTrue:
      Consume(tTrue, &t);
      n = new CAstConstant(t, tm->GetBool(), 1);
      break;

    case tFalse:
      Consume(tFalse, &t);
      n = new CAstConstant(t, tm->GetBool(), 0);
      break;

    case tNumber:
    {
      Consume(tNumber, &t);
      errno = 0;
      long long v = strtoll(t.GetValue().c_str(), NULL, 10);
      if (errno != 0) SetError(t, "invalid number.");

      // integer range validation check.
      if(v > 2147483648)
        SetError(t, "integer constant outside valid range.");

      n = new CAstConstant(t, tm->GetInt(), v);
      break;
    }

    case tIdent:
    {
      Consume(tIdent, &t);

      if(_scanner->Peek().GetType() == tLBrak) { // subroutineCall
        Consume(tLBrak);
        CAstFunctionCall *f;

        // If subroutineCall calls undefined procedure/function, then set error.
        if(symtab->FindSymbol(t.GetValue(),sLocal) == NULL && symtab->FindSymbol(t.GetValue(), sGlobal) != NULL) {
          // Check if symbol is procedure.
          if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sGlobal)) == NULL)
            SetError(t, "invalid procedure/function identifier.");

          f = new CAstFunctionCall(t, dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sGlobal)));
        }
        else if(symtab->FindSymbol(t.GetValue(), sLocal) != NULL) {
          // Check if symbol is procedure.
          if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sLocal)) == NULL)
            SetError(t, "invalid procedure/function identifier.");

          f = new CAstFunctionCall(t, dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sLocal)));
        }
        else
          SetError(t, "undefined identifier.");

        assert(f != NULL);

        if(isExpr(_scanner->Peek())) {
          CAstExpression *expr = expression(s);
          assert(expr != NULL);
 
          // If array, then addressed.
          if(expr->GetType()->IsArray())
            expr = new CAstSpecialOp(expr->GetToken(), opAddress, expr, NULL);

          f->AddArg(expr);

          while(_scanner->Peek().GetType() == tComma) {
            Consume(tComma);
            expr = expression(s);
            assert(expr != NULL);
 
            // If array, then addressed.
            if(expr->GetType()->IsArray())
              expr = new CAstSpecialOp(expr->GetToken(), opAddress, expr, NULL);

            f->AddArg(expr);
          }
        }
        Consume(tRBrak);

        n = f;
      }
      else { // qualident
        if(_scanner->Peek().GetType() == tLSBrak) { // It means array
          CAstArrayDesignator *f;

          if(symtab->FindSymbol(t.GetValue(), sLocal) == NULL && symtab->FindSymbol(t.GetValue(), sGlobal) != NULL) {
            // Check if symbol is procedure.
            if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sGlobal)) != NULL)
              SetError(t, "designator expected.");

            f = new CAstArrayDesignator(t, symtab->FindSymbol(t.GetValue(), sGlobal));
          }
          else if(symtab->FindSymbol(t.GetValue(), sLocal) != NULL) {
            // Check if symbol is procedure.
            if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sLocal)) != NULL)
              SetError(t, "designator expected");

            f = new CAstArrayDesignator(t, symtab->FindSymbol(t.GetValue(), sLocal));
          }
          else {
            SetError(t, "undefined identifier.");
          }
          
          while(_scanner->Peek().GetType() == tLSBrak) {
            Consume(tLSBrak);

            CAstExpression *expr = expression(s);
            assert(expr != NULL);
            f->AddIndex(expr);

            Consume(tRSBrak);
          }

          f->IndicesComplete();

          n = f;
        } // non-array case.
        else {
          if(symtab->FindSymbol(t.GetValue(), sLocal) == NULL && symtab->FindSymbol(t.GetValue(), sGlobal) != NULL) {
            // Check if symbol is procedure.
            if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sGlobal)) != NULL) {
              SetError(t, "designator expected.");
            }
            n = new CAstDesignator(t, symtab->FindSymbol(t.GetValue(), sGlobal));
          }
          else if(symtab->FindSymbol(t.GetValue(), sLocal) != NULL) {
            // Check if symbol is procedure.
            if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sLocal)) != NULL) {
              SetError(t, "designator expected.");
            }
            n = new CAstDesignator(t, symtab->FindSymbol(t.GetValue(), sLocal));
          }
          else
            SetError(t, "undefined identifier.");
        }
      }
      break;
    }

    case tString:
      Consume(tString, &t);
      n = new CAstStringConstant(t, t.GetValue(), s);
      break;

    case tCharacter:
    {
      Consume(tCharacter, &t);
      char res;

      // If character length is 0, it means character is '\0' because invalid character cases are handled in scanner.
      if(t.GetValue().length() == 0)
        res = '\0';
      else if(t.GetValue().length() == 1) {
        if(t.GetValue().at(0) != '\\')
          res = t.GetValue().at(0);
        else SetError(t, "wrong character");
      }
      // unescape.
      else if(t.GetValue().length() == 2) {
        if(t.GetValue().at(0) == '\\') {
          if(t.GetValue().at(1) == 'n') {
            res = '\n';
          }
          else if(t.GetValue().at(1) == 't') {
            res = '\t';
          }
          else if(t.GetValue().at(1) == '"') {
            res = '"';
          }
          else if(t.GetValue().at(1) == '\'') {
            res = '\'';
          }
          else if(t.GetValue().at(1) == '\\') {
            res = '\\';
          }
          else if(t.GetValue().at(1) == '0') {
            res = '\0';
          }
          else
            SetError(t, "wrong character");
        }
      }
      else SetError(t, "wrong character");

      n = new CAstConstant(t, tm->GetChar(), (long long)res);
      break;
    }

    case tLBrak:
      Consume(tLBrak);
      n = expression(s);
      Consume(tRBrak);
      break;

    case tEMark:
      Consume(tEMark, &t);
      n = new CAstUnaryOp(t, opNot, factor(s));
      break;

    default:
//      cout << "got " << _scanner->Peek() << endl;
      SetError(_scanner->Peek(), "factor expected.");
      break;
  }

  return n;
}
Example #13
0
CAstExpression* CParser::simpleexpr(CAstScope *s) {
  //
  // simpleexpr ::= ["+" | "-"] term { termOp term }.
  // termOp = {+, -, ||}.
  //
  
  CAstExpression *n = NULL;
  EOperation eOp;
  CToken tt;

  // unary operation case.
  if(_scanner->Peek().GetType() == tTermOp) {
    CToken t, tOp;

    Consume(tTermOp, &tOp);

    if(tOp.GetValue() == "+")
      eOp = opPos;
    else if(tOp.GetValue() == "-")
      eOp = opNeg;
    else
      SetError(tOp, "invalid term operator");

    CAstExpression *tmp = term(s);

    // If term is constant, then negate it. -> Simple.
    if(dynamic_cast<CAstConstant *>(tmp) != NULL && tmp->GetType()->IsInt()) {
      if(eOp == opNeg)
        dynamic_cast<CAstConstant *>(tmp)->SetValue(-dynamic_cast<CAstConstant *>(tmp)->GetValue());
      
      n = tmp;
    }
    else {
      n = new CAstUnaryOp(tOp, eOp, tmp);
    }

    while(_scanner->Peek().GetType() == tTermOp) {
      CAstExpression *l = n, *r;
      Consume(tTermOp, &tt);
      r = term(s);

      if(tt.GetValue() == "+") {
        n = new CAstBinaryOp(tt, opAdd, l, r);
      }
      else if(tt.GetValue() == "-") {
        n = new CAstBinaryOp(tt, opSub, l, r);
      }
      else {
        n = new CAstBinaryOp(tt, opOr, l, r);
      }
    }

    return n;
  }
  else { // non-unary case.
    n = term(s);

    while (_scanner->Peek().GetType() == tTermOp) {
      CToken t;
      CAstExpression *l = n, *r;

      Consume(tTermOp, &tt);

      r = term(s);
      
      if(tt.GetValue() == "+") {
        n = new CAstBinaryOp(tt, opAdd, l, r);
      }
      else if(tt.GetValue() == "-") {
        n = new CAstBinaryOp(tt, opSub, l, r);
      }
      else {
        n = new CAstBinaryOp(tt, opOr, l, r);
      }
    }

    return n;
  }
}
Example #14
0
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;
}