Пример #1
0
        public void Emit(CompilationContext context)
        {
            context.EmitComment(";Function call");

            var expressionType = ((IHasType)Tokens[0]).GetExpressionType(context);

            if (!(expressionType.BaseType is FunctionTypeDef))
            {
                throw new Exception("Can't call expression type: " + expressionType + " as a function");
            }

            FunctionTypeDef functionType = (FunctionTypeDef)expressionType.BaseType;
            ExpressionType  returnType   = functionType.ReturnType;

            //List<ExpressionType> parameterTypes = functionType.ArgumentTypes;

            if (returnType.GetSize() > 4)
            {
                //Make space for return value in caller stack
                //context.EmitInstruction(new IRMoveImmediate() { To = "eax", Value = new ImmediateValue(function.ReturnType.GetSize()) });
                //context.EmitInstruction(new IRAdd() { Left = "sp", Right = "eax", To = "sp" });
                throw new LargeReturnValuesNotSupportedException();
            }

            //Push base pointer on stack
            context.EmitInstruction(new IRPushRegister()
            {
                From = "bp"
            });

            //Save registers (TODO: Not actually needed until we have smarter allocation that uses registers instead of stack)
            //context.EmitInstruction(new IRPushRegister() { From = "eax" });
            //context.EmitInstruction(new IRPushRegister() { From = "ebx" });
            //context.EmitInstruction(new IRPushRegister() { From = "ecx" });
            //context.EmitInstruction(new IRPushRegister() { From = "edx" });

            int argumentCount = Tokens.Count - 1;
            int argumentsSize = 0;

            if (argumentCount != functionType.ArgumentTypes.Count)
            {
                throw new ArgumentCountMismatchException(Tokens[0].ToString(), functionType.ArgumentTypes.Count, argumentCount);
            }

            if (Tokens.Count > 1)
            {
                //Push arguments on stack in reverse order
                for (int i = Tokens.Count - 1; i > 0; i--)
                {
                    var argExpressionType   = ((IHasType)Tokens[i]).GetExpressionType(context);
                    var paramExpressionType = functionType.ArgumentTypes[functionType.ArgumentTypes.Count - 1 - (Tokens.Count - 1 - i)];

                    TypeChecking.CheckExpressionTypesMatch(paramExpressionType, argExpressionType);

                    //Push argument value on stack
                    ((ICodeEmitter)Tokens[i]).Emit(context);

                    argumentCount++;
                    argumentsSize += argExpressionType.GetSize();
                }
            }

            var returnLabel = new LabelAddressValue(context.CreateNewLabel());

            //Address of function -> eax
            ((ICodeEmitter)Tokens[0]).Emit(context);
            context.EmitInstruction(new IRPop()
            {
                To = "eax"
            });

            //Set base pointer to be the top of current function's stack which will be the bottom
            //of the called function's stack
            context.EmitInstruction(new IRMoveRegister()
            {
                From = "sp", To = "bp"
            });

            //Push return address
            context.EmitInstruction(new IRPushImmediate()
            {
                Value = returnLabel
            });

            //Jump to function
            context.EmitInstruction(new IRJumpRegister()
            {
                Address = "eax"
            });

            //Resume here, reclaim space from arguments pushed on stack
            context.EmitLabel(returnLabel.Value);
            context.EmitInstruction(new IRMoveImmediate()
            {
                To = "ebx", Value = new ImmediateValue(argumentsSize)
            });
            context.EmitInstruction(new IRSub()
            {
                To = "sp", Left = "sp", Right = "ebx"
            });

            //Restore registers (TODO: Not actually needed until we have smarter allocation that uses registers instead of stack)
            //context.EmitInstruction(new IRPop() { To = "edx" });
            //context.EmitInstruction(new IRPop() { To = "ecx" });
            //context.EmitInstruction(new IRPop() { To = "ebx" });
            //context.EmitInstruction(new IRPop() { To = "eax" });

            //Reset base pointer
            context.EmitInstruction(new IRPop()
            {
                To = "bp"
            });

            if (returnType.GetSize() > 4)
            {
                //Return value is already on stack
                throw new LargeReturnValuesNotSupportedException();
            }
            else if (returnType.GetSize() > 0)
            {
                //Return value in eax, put on stack
                context.EmitInstruction(new IRPushRegister()
                {
                    From = "eax"
                });
            }
        }
Пример #2
0
        public void Emit(CompilationContext context)
        {
            context.EmitComment(";Boolean expression");

            ((ICodeEmitter)Tokens[0]).Emit(context);

            var expressionType = ((IHasType)Tokens[0]).GetExpressionType(context);

            if (Tokens.Count > 1)
            {
                TypeChecking.CheckExpressionTypeIsBoolean(expressionType);
            }

            for (int i = 1; i < Tokens.Count; i += 2)
            {
                string op = ((DefaultLanguageTerminalToken)Tokens[i]).Value;

                ((ICodeEmitter)Tokens[i + 1]).Emit(context);

                expressionType = ((IHasType)Tokens[i + 1]).GetExpressionType(context);

                TypeChecking.CheckExpressionTypeIsBoolean(expressionType);

                context.EmitInstruction(new IRPop()
                {
                    To = "ebx"
                });
                context.EmitInstruction(new IRPop()
                {
                    To = "eax"
                });

                var trueLabel = new LabelAddressValue(context.CreateNewLabel());

                switch (op)
                {
                case "&&":
                    context.EmitInstruction(new IRAnd()
                    {
                        Left = "eax", Right = "ebx", To = "ecx"
                    });
                    context.EmitInstruction(new IRCompareImmediate()
                    {
                        Left = "ecx", Right = new ImmediateValue(0)
                    });
                    context.EmitInstruction(new IRJumpNE()
                    {
                        Address = trueLabel
                    });
                    break;

                case "||":
                    context.EmitInstruction(new IROr()
                    {
                        Left = "eax", Right = "ebx", To = "ecx"
                    });
                    context.EmitInstruction(new IRCompareImmediate()
                    {
                        Left = "ecx", Right = new ImmediateValue(0)
                    });
                    context.EmitInstruction(new IRJumpNE()
                    {
                        Address = trueLabel
                    });
                    break;
                }

                var skipTrueLabel = new LabelAddressValue(context.CreateNewLabel());

                context.EmitInstruction(new IRPushImmediate()
                {
                    Value = new ImmediateValue(0)
                });
                context.EmitInstruction(new IRJumpImmediate()
                {
                    Address = skipTrueLabel
                });
                context.EmitLabel(trueLabel.Value);
                context.EmitInstruction(new IRPushImmediate()
                {
                    Value = new ImmediateValue(1)
                });
                context.EmitLabel(skipTrueLabel.Value);
            }
        }
Пример #3
0
        public void Emit(CompilationContext context)
        {
            context.EmitComment(";Equality expression");

            ((ICodeEmitter)Tokens[0]).Emit(context);

            var t1ExpressionType = ((IHasType)Tokens[0]).GetExpressionType(context);

            for (int i = 1; i < Tokens.Count; i += 2)
            {
                string op = ((DefaultLanguageTerminalToken)Tokens[i]).Value;

                ((ICodeEmitter)Tokens[i + 1]).Emit(context);

                var t2ExpressionType = ((IHasType)Tokens[i + 1]).GetExpressionType(context);

                TypeChecking.CheckExpressionTypesMatch(t1ExpressionType, t2ExpressionType);
                t1ExpressionType = t2ExpressionType;

                context.EmitInstruction(new IRPop()
                {
                    To = "ebx"
                });
                context.EmitInstruction(new IRPop()
                {
                    To = "eax"
                });

                context.EmitInstruction(new IRCompareRegister()
                {
                    Left = "eax", Right = "ebx"
                });

                var trueLabel = new LabelAddressValue(context.CreateNewLabel());

                switch (op)
                {
                case "==":
                    context.EmitInstruction(new IRJumpEQ()
                    {
                        Address = trueLabel
                    });
                    break;

                case "!=":
                    context.EmitInstruction(new IRJumpNE()
                    {
                        Address = trueLabel
                    });
                    break;

                case ">":
                    context.EmitInstruction(new IRJumpGT()
                    {
                        Address = trueLabel
                    });
                    break;

                case "<":
                    context.EmitInstruction(new IRJumpLT()
                    {
                        Address = trueLabel
                    });
                    break;

                case ">=":
                    context.EmitInstruction(new IRJumpGE()
                    {
                        Address = trueLabel
                    });
                    break;

                case "<=":
                    context.EmitInstruction(new IRJumpLE()
                    {
                        Address = trueLabel
                    });
                    break;
                }

                var skipTrueLabel = new LabelAddressValue(context.CreateNewLabel());

                context.EmitInstruction(new IRPushImmediate()
                {
                    Value = new ImmediateValue(0)
                });
                context.EmitInstruction(new IRJumpImmediate()
                {
                    Address = skipTrueLabel
                });
                context.EmitLabel(trueLabel.Value);
                context.EmitInstruction(new IRPushImmediate()
                {
                    Value = new ImmediateValue(1)
                });
                context.EmitLabel(skipTrueLabel.Value);
            }
        }