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

            context.ReportReturnStatement();

            var returnExpressionType = new ExpressionType()
            {
                BaseType = new TypeDef()
                {
                    Name = "void", Size = 0
                }
            };

            if (Tokens.Count > 1)
            {
                returnExpressionType = ((IHasType)Tokens[1]).GetExpressionType(context);

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

                //(Caller saves registers)

                if (returnExpressionType.GetSize() > 4)
                {
                    //Return value gets placed space allocated in caller's stack
                    throw new Exception("Large return values not supported");
                }
                else
                {
                    //Return value from function goes in eax
                    context.EmitInstruction(new IRPop()
                    {
                        To = "eax"
                    });
                }
            }

            int localVarsSize = context.GetFunctionLocalVarSize();

            //Reclaim local variables from stack space

            context.EmitInstruction(new IRMoveImmediate()
            {
                To = "ebx", Value = new ImmediateValue(localVarsSize)
            });
            context.EmitInstruction(new IRSub()
            {
                To = "sp", Left = "sp", Right = "ebx"
            });

            TypeChecking.CheckExpressionTypesMatch(context.GetCurrentFunctionReturnExpressionType(), returnExpressionType);

            if (context.IsEntryPointFunction)
            {
                //DONT WANT THIS. HALT JUST STOPS CPU COMPLETELY NOW
                //At this point the return value of the function is still in eax and we simple halt execution
                //as the exe has run to completion
                //context.EmitInstruction(new IRHalt());
            }
            else
            {
                //Pop return address off stack and jump
                context.EmitInstruction(new IRRet());
            }
        }
Пример #2
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"
                });
            }
        }