AsmBlock* NUnaryOperator::compile(AsmGenerator& context) { AsmBlock* block = new AsmBlock(); // Add file and line information. *block << this->getFileAndLineState(); // When an expression is evaluated, the result goes into the A register. AsmBlock* rhs = this->rhs.compile(context); // get type IType* rhsType = this->rhs.getExpressionType(context); if (!rhsType->isBasicType()) { throw new CompilerException(this->line, this->file, "Invalid operand to unary operation. (have '" + rhsType->getName() + "')"); } // Move the value into A *block << *rhs; delete rhs; // Now do the appropriate operation. AsmBlock* compiledOp; switch (this->op) { case ADD: /* TODO integer promotion */ compiledOp = rhsType->plus(context, 'A'); break; /* unary negative: "A = -A" */ case SUBTRACT: // A = 0 - A compiledOp = rhsType->minus(context, 'A'); break; /* unary bitwise negate: "A = ~A" */ case BITWISE_NEGATE: compiledOp = rhsType->bnot(context, 'A'); break; /* boolean negate: A = !A */ case NEGATE: compiledOp = rhsType->lnot(context, 'A'); break; default: throw new CompilerException(this->line, this->file, "Unknown unary operations requested."); } *block << *compiledOp; return block; }
/* NFunctionSignature::calculateSignature() */ std::string NMethodCall::calculateSignature(AsmGenerator& context) { std::string sig = "("; for (ExpressionList::const_iterator i = this->arguments.begin(); i != this->arguments.end(); i++) { if (i != this->arguments.begin()) { sig = sig + ","; } IType* type = (*i)->getExpressionType(context); sig = sig + type->getName(); } sig = sig + ")"; return sig; }
AsmBlock* NPostIncDec::compile(AsmGenerator& context) { AsmBlock* block = new AsmBlock(); // We have to compile and reference, but the reference function allready compiles // and evaluates, thus we use the reference not the value. AsmBlock* reference = this->expr.reference(context); *block << *reference; delete reference; // get type IType* exprType = this->expr.getExpressionType(context); // Type checking if ((!exprType->isPointer()) && (!exprType->isBasicType())) { throw new CompilerException(this->line, this->file, "Invalid operand to post increase/decrease operation. (have '" + exprType->getName() + "')"); } *block << " SET B, A" << std::endl; // return old value in A *block << *(exprType->loadFromRef(context, 'B', 'A')); // increment/decrement switch (this->op) { case INCREMENT: *block << *(exprType->inc(context, 'B')); break; case DECREMENT: *block << *(exprType->dec(context, 'B')); break; default: throw new CompilerException(this->line, this->file, "Unknown Post-Increase-Decrease operation requested."); } return block; }
AsmBlock* NAssignment::compile(AsmGenerator& context) { AsmBlock* block = new AsmBlock(); // Add file and line information. *block << this->getFileAndLineState(); // When an assignment expression is referenced, the memory // address of the target goes into A. AsmBlock* las = this->lhs.reference(context); *block << *las; // get lhs type IType* lhsType = this->lhs.getExpressionType(context); // push memory address *block << " SET PUSH, A" << std::endl; delete las; // handle regular assignment as special case if (this->op == ASSIGN_EQUAL) { // When an expression is evaluated, the result goes into the A register. AsmBlock* rhs = this->rhs.compile(context); *block << *rhs; delete rhs; // get rhs type IType* rhsType = this->rhs.getExpressionType(context); // cast to rhs to lhs type if (rhsType->implicitCastable(context, lhsType)) { *block << *(rhsType->implicitCast(context, lhsType, 'A')); } else { throw new CompilerException(this->line, this->file, "Unable to implicitly cast '" + rhsType->getName() + "' to '" + lhsType->getName() + "'"); } // Pop the address of lhs into B if (context.isAssemblerDebug()) { // Put the value into B and clear the // stack positions as we do so. *block << " SET B, PEEK" << std::endl; *block << " SET PEEK, 0" << std::endl; *block << " ADD SP, 1" << std::endl; } else { // Not debugging, put the values into B. *block << " SET B, POP" << std::endl; } // save the value A to [B] *block << *(lhsType->saveToRef(context, 'A', 'B')); } else { // When an expression is evaluated, the result goes into the A register. AsmBlock* rhs = this->rhs.compile(context); *block << *rhs; delete rhs; // get rhs type IType* rhsType = this->rhs.getExpressionType(context); // Check if both types are of a basic type bool isPointerOp = false; if (lhsType->isPointer() && rhsType->isBasicType()) { // pointer op: p += i, or p -= i isPointerOp = true; if (this->op != ASSIGN_ADD && this->op != ASSIGN_SUBTRACT) { throw new CompilerException(this->line, this->file, "Invalid operands to assign operation. (have '" + lhsType->getName() + "' and '" + rhsType->getName() + "')"); } } else if ((!rhsType->isBasicType()) || (!lhsType->isBasicType())) { throw new CompilerException(this->line, this->file, "Invalid operands to assign operation. (have '" + lhsType->getName() + "' and '" + rhsType->getName() + "')"); } if (!isPointerOp) { // cast to rhs to lhs type if (rhsType->implicitCastable(context, lhsType)) { *block << *(rhsType->implicitCast(context, lhsType, 'A')); } else { throw new CompilerException(this->line, this->file, "Unable to implicitly cast '" + rhsType->getName() + "' to '" + lhsType->getName() + "'"); } } // move rhs over to register B *block << " SET B, A" << std::endl; // get referenced value and put it in A *block << " SET A, PEEK" << std::endl; *block << *(lhsType->loadFromRef(context, 'A', 'A')); // Now do the appropriate operation. // TODO a lot of assignment operations are missing !! // TODO type specific ops switch (this->op) { case ASSIGN_ADD: *block << *(lhsType->add(context, 'A', 'B')); break; case ASSIGN_SUBTRACT: *block << *(lhsType->sub(context, 'A', 'B')); break; case ASSIGN_MULTIPLY: *block << *(lhsType->mul(context, 'A', 'B')); break; case ASSIGN_DIVIDE: *block << *(lhsType->div(context, 'A', 'B')); break; case ASSIGN_MOD: *block << *(lhsType->mod(context, 'A', 'B')); break; case ASSIGN_BAND: *block << *(lhsType->band(context, 'A', 'B')); break; case ASSIGN_BOR: *block << *(lhsType->bor(context, 'A', 'B')); break; case ASSIGN_BXOR: *block << *(lhsType->bxor(context, 'A', 'B')); break; case ASSIGN_SHL: *block << *(lhsType->shl(context, 'A', 'B')); break; case ASSIGN_SHR: *block << *(lhsType->shr(context, 'A', 'B')); break; default: throw new CompilerException(this->line, this->file, "Unknown assignment operation requested."); } // Pop reference from stack // If debugging, clear the value as we POP them. if (context.isAssemblerDebug()) { // Put the value into B and clear the // stack position as we do so. *block << " SET B, PEEK" << std::endl; *block << " SET PEEK, 0" << std::endl; *block << " ADD SP, 1" << std::endl; } else { // Not debugging, put the values into B. *block << " SET B, POP" << std::endl; } // Move the value into the target address. *block << *(lhsType->saveToRef(context, 'A', 'B')); } return block; }
AsmBlock* TGenericBasicType::compileBinaryOperator(NBinaryOperator* binopNode, AsmGenerator& context) { AsmBlock* block = new AsmBlock(); // get types IType* lhsType = binopNode->lhs.getExpressionType(context); IType* rhsType = binopNode->rhs.getExpressionType(context); // If debugging, clear the values as we POP them. if (context.isAssemblerDebug()) { // Put the values into A and B and clear the // stack positions as we do so. *block << *(rhsType->popStackCleanReturn(context, 'B')); *block << *(lhsType->popStackCleanReturn(context, 'A')); } else { // Not debugging, put the values into A and B. *block << *(rhsType->popStackReturn(context, 'B')); *block << *(lhsType->popStackReturn(context, 'A')); } // get promoted type and cast values to result type IType* commonType = TGenericBasicType::promoteTypes(lhsType, rhsType); if (lhsType != commonType) { // cast lhsType if (lhsType->implicitCastable(context, commonType)) { *block << *(lhsType->implicitCast(context, commonType, 'A')); } else { throw new CompilerException(binopNode->line, binopNode->file, "Unable to implicitly cast '" + lhsType->getName() + "' to '" + commonType->getName() + "'"); } } else if (rhsType != commonType) { // cast rhsType if (rhsType->implicitCastable(context, commonType)) { *block << *(rhsType->implicitCast(context, commonType, 'B')); } else { throw new CompilerException(binopNode->line, binopNode->file, "Unable to implicitly cast '" + rhsType->getName() + "' to '" + commonType->getName() + "'"); } } // Now do the appropriate operation. switch (binopNode->op) { case ADD: *block << *(commonType->add(context, 'A', 'B')); break; case SUBTRACT: *block << *(commonType->sub(context, 'A', 'B')); break; case STAR: *block << *(commonType->mul(context, 'A', 'B')); break; case SLASH: *block << *(commonType->div(context, 'A', 'B')); break; case PERCENT: *block << *(commonType->mod(context, 'A', 'B')); break; case BOOLEAN_AND: *block << *(commonType->land(context, 'A', 'B')); break; case BOOLEAN_OR: *block << *(commonType->lor(context, 'A', 'B')); break; case BINARY_AND: *block << *(commonType->band(context, 'A', 'B')); break; case BINARY_OR: *block << *(commonType->bor(context, 'A', 'B')); break; case BINARY_XOR: *block << *(commonType->bxor(context, 'A', 'B')); break; case BINARY_LEFT_SHIFT: *block << *(commonType->shl(context, 'A', 'B')); break; case BINARY_RIGHT_SHIFT: *block << *(commonType->shr(context, 'A', 'B')); break; case COMPARE_EQUAL: *block << *(commonType->eq(context, 'A', 'B')); break; case COMPARE_NOT_EQUAL: *block << *(commonType->neq(context, 'A', 'B')); break; case COMPARE_LESS_THAN: *block << *(commonType->lt(context, 'A', 'B')); break; case COMPARE_LESS_THAN_EQUAL: *block << *(commonType->le(context, 'A', 'B')); break; case COMPARE_GREATER_THAN: *block << *(commonType->gt(context, 'A', 'B')); break; case COMPARE_GREATER_THAN_EQUAL: *block << *(commonType->ge(context, 'A', 'B')); break; default: throw new CompilerException(binopNode->line, binopNode->file, "Unknown binary operations requested."); } return block; }