コード例 #1
0
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;
}
コード例 #2
0
ファイル: NAssignment.cpp プロジェクト: jathd/DCPUToolchain
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;
}
コード例 #3
0
ファイル: NMethodCall.cpp プロジェクト: jathd/DCPUToolchain
AsmBlock* NMethodCall::compile(AsmGenerator& context)
{
    AsmBlock* block = new AsmBlock();

    // Add file and line information.
    *block << this->getFileAndLineState();

    // Get the function declaration.
    bool isDirect = true;
    NFunctionSignature* funcsig = (NFunctionDeclaration*)context.getFunction(this->id.name);

    // FIXME: get rid of the use of NType for function signatures!!
    if (funcsig == NULL)
    {
        // Try and get a variable with matching signature then.
        TypePosition varpos = context.m_CurrentFrame->getPositionOfVariable(this->id.name);

        if (!varpos.isFound())
            throw new CompilerException(this->line, this->file, "Neither a function nor a function pointer was found by the name '" + this->id.name + "'.");

        NType* vartype = (NType*)context.m_CurrentFrame->getTypeOfVariable(this->id.name);

        if (vartype->cType != "expression-identifier-type-function")
            throw new CompilerException(this->line, this->file, "Unable to call variable '" + this->id.name + "' as it is not a function pointer.");

        funcsig = (NFunctionSignature*)((NFunctionPointerType*)vartype);
        isDirect = false;
    }



    // check if the called function matches the signature size of this
    // method call
    if (this->arguments.size() != funcsig->arguments.size())
    {
        throw new CompilerException(this->line, this->file,
                                    "Unable to find function\n"
                                    "with singature:                 "
                                    + this->id.name + this->calculateSignature(context)
                                    + "\n"
                                    + "Candidates are:               "
                                    + this->id.name + funcsig->getSignature());
    }

    // Get the stack table of this method.
    StackFrame* frame = context.generateStackFrameIncomplete(funcsig);

    // Get a random label for our jump-back point.
    std::string jmpback = context.getRandomLabel("callback");

    // Evaluate each of the argument expressions in reverse
    // TODO make it depend on the typePosition somehow
    //  this here has to be exactly reverse to the order in the
    //  parameter stack frame and thus the TypePosition
    for (int i = this->arguments.size() - 1; i >= 0; --i)
    {
        // Compile the expression.
        AsmBlock* inst = this->arguments[i]->compile(context);
        *block << *inst;
        delete inst;

        IType* instType = this->arguments[i]->getExpressionType(context);

        // check types and cast implicitly
        IType* parameterType = funcsig->arguments[i]->type;
        if (instType->implicitCastable(context, parameterType))
        {
            // do cast
            *block << *(instType->implicitCast(context, parameterType, 'A'));
        }
        else
        {
            throw new CompilerException(this->line, this->file,
                                        "Unable to find function\n"
                                        "with singature:                 "
                                        + this->id.name + this->calculateSignature(context)
                                        + "\n"
                                        + "Candidates are:               "
                                        + this->id.name + funcsig->getSignature());
        }

        // Push the result onto the stack.
        *block << *(parameterType->pushStack(context, 'A'));
    }

    // Initialize the stack for this method.
    if (isDirect)
    {
        *block <<  "    SET X, cfunc_" << this->id.name << std::endl;
        *block <<  "    ADD X, 2" << std::endl;
    }
    else
    {
        TypePosition varpos = context.m_CurrentFrame->getPositionOfVariable(this->id.name);
        *block <<  varpos.pushAddress('X');
        *block <<  "    SET X, [X]" << std::endl;
        *block <<  "    ADD X, 2" << std::endl;
    }

    *block <<  "    SET X, [X]" << std::endl;
    *block <<  "    SET Z, " << jmpback << std::endl;
    *block <<  "    JSR _stack_caller_init_overlap" << std::endl;

    // Then call the actual method and insert the return label.
    if (isDirect)
    {
        *block <<  "    SET PC, cfunc_" << this->id.name << std::endl;
    }
    else
    {
        // we are referencing the previous stack frame here
        // => parameter previousStackFrame=true
        TypePosition varpos = context.m_CurrentFrame->getPositionOfVariable(this->id.name, true);
        *block <<  varpos.pushAddress('X');
        *block <<  "    SET X, [X]" << std::endl;
        *block <<  "    SET PC, X" << std::endl;

        // TODO: In debug mode, there should be additional checks here to see if
        //   the value that is going to be jumped to is 0 (NULL) so that it can
        //   be reported back without doing weird stuff (like restarting the
        //   program!)
    }

    *block <<  ":" << jmpback << std::endl;

    // Clean up frame.
    context.finishStackFrame(frame);

    return block;
}