Esempio n. 1
0
        public void Emit(CompilationContext context)
        {
            context.EmitComment(";Multiplicative expression");

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

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

            if (Tokens.Count > 1)
            {
                TypeChecking.CheckExpressionTypeIsNumeric(t1ExpressionType);
            }

            for (int i = 1; i < Tokens.Count; i += 2)
            {
                ((ICodeEmitter)Tokens[i + 1]).Emit(context);

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

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

                t1ExpressionType = t2ExpressionType;

                string op = ((DefaultLanguageTerminalToken)Tokens[i]).Value;

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

                switch (op)
                {
                case "*":
                    context.EmitInstruction(new IRMult()
                    {
                        Left = "eax", Right = "ebx", To = "ecx"
                    });
                    break;

                case "/":
                    context.EmitInstruction(new IRDiv()
                    {
                        Left = "eax", Right = "ebx", To = "ecx"
                    });
                    break;
                }

                context.EmitInstruction(new IRPushRegister()
                {
                    From = "ecx"
                });
            }
        }
Esempio n. 2
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());
            }
        }
Esempio n. 3
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"
                });
            }
        }
Esempio n. 4
0
        public void Emit(CompilationContext context)
        {
            context.EmitComment(";Variable definition");

            var    type         = ((IHasType)Tokens[0]).GetExpressionType(context);
            string variableName = ((IdentifierToken)Tokens[1]).Name;

            if (type.IsArray && type.ArrayLength == -1)
            {
                throw new MissingArraySizeSpecifierException(variableName);
            }

            context.AddVariableSymbol(variableName, type, IsStatic, IsExported, IsExtern);

            if (!IsStatic && !context.InFunctionScope())
            {
                throw new Exception("Cannot define non static variable outside of function scope.");
            }

            if (Tokens.Count > 2)
            {
                var assignmentExpressionType = ((IHasType)Tokens[3]).GetExpressionType(context);

                var variable = context.GetVariable(variableName);

                if (variable.Type.GetSize() == 0)
                {
                    throw new VoidAssignmentException("to");
                }
                else if (assignmentExpressionType.GetSize() == 0)
                {
                    throw new VoidAssignmentException("from");
                }

                TypeChecking.CheckExpressionTypesMatch(variable.Type, assignmentExpressionType);

                //Special case for assignment of string literal to byte array:
                //  Don't emit string constant normally (which would add it as a string constant in the data section),
                //  instead copy the string to the memory occupied by tge byte array itself
                if (assignmentExpressionType.BaseType is StringLiteralTypeDef && variable.Type.IsArray)
                {
                    string stringLiteral = ((StringLiteralTypeDef)assignmentExpressionType.BaseType).Value;

                    if (assignmentExpressionType.ArrayLength > variable.Type.ArrayLength)
                    {
                        throw new Exception("The string '" + stringLiteral + "' is too large to be assigned by value to the left hand expression.");
                    }

                    //Put start address to copy string value to into eax
                    if (variable.Address is StackAddressValue)
                    {
                        context.EmitInstruction(new IRMoveImmediate()
                        {
                            To = "ebx", Value = new ImmediateValue(variable.Address.Value)
                        });
                        context.EmitInstruction(new IRAdd()
                        {
                            To = "ebx", Left = "bp", Right = "ebx"
                        });
                        context.EmitInstruction(new IRPushRegister()
                        {
                            From = "ebx"
                        });
                    }
                    else
                    {
                        context.EmitInstruction(new IRPushImmediate()
                        {
                            Value = variable.Address
                        });
                    }

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

                    for (int i = 0; i < assignmentExpressionType.ArrayLength; i++)
                    {
                        byte charValue = i < stringLiteral.Length ? (byte)stringLiteral[i] : (byte)0;

                        //Put char value into ebx
                        context.EmitInstruction(new IRMoveImmediate()
                        {
                            To = "ebx", Value = new ImmediateValue(charValue), OperandSize = 1
                        });
                        //Store char value into address [eax + char offset]
                        context.EmitInstruction(new IRStoreRegisterPlusImmediate()
                        {
                            To = "eax", Offset = new ImmediateValue(i), From = "ebx", OperandSize = 1
                        });
                    }
                }
                else
                {
                    if (assignmentExpressionType.GetSize() > 4)
                    {
                        //Memory copy

                        //Dest address -> eax
                        throw new Exception("TODO: Copy large values to stack variables");
                        //context.EmitInstruction(new IRMoveImmediate() { To = "eax", Value = variable.Address }); //STACK!!!!

                        //Source address -> ebx
                        //((IHasAddress)Tokens[3]).PushAddress(context);

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

                        //context.EmitInstruction(new IRMemCopy() { From = "ebx", To = "eax", Length = new ImmediateValue(assignmentExpressionType.GetSize()) });
                    }
                    else
                    {
                        //Copy using register
                        ((ICodeEmitter)Tokens[3]).Emit(context);

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

                        if (variable.Address is StackAddressValue)
                        {
                            context.EmitInstruction(new IRStoreRegisterPlusImmediate()
                            {
                                From = "eax", To = "bp", Offset = new ImmediateValue(variable.Address.Value), OperandSize = assignmentExpressionType.GetSize()
                            });
                        }
                        else
                        {
                            context.EmitInstruction(new IRStoreImmediate()
                            {
                                From = "eax", To = variable.Address, OperandSize = assignmentExpressionType.GetSize()
                            });
                        }
                    }
                }
            }
        }
Esempio n. 5
0
        public void Emit(CompilationContext context)
        {
            context.EmitComment(";Assignment");

            var leftSideExpressionType  = ((IHasType)Tokens[0]).GetExpressionType(context);
            var rightSideExpressionType = ((IHasType)Tokens[2]).GetExpressionType(context);

            if (leftSideExpressionType.IsArray)
            {
                throw new TypeMismatchException(new ExpressionType()
                {
                    IsArray = true, BaseType = leftSideExpressionType.BaseType, ArrayLength = leftSideExpressionType.ArrayLength
                }, rightSideExpressionType);
            }

            if (leftSideExpressionType.GetSize() == 0)
            {
                throw new VoidAssignmentException("to");
            }
            else if (rightSideExpressionType.GetSize() == 0)
            {
                throw new VoidAssignmentException("from");
            }

            TypeChecking.CheckExpressionTypesMatch(leftSideExpressionType, rightSideExpressionType);

            //Special case for assignment of string literal to byte array:
            //  Don't emit string constant normally (which would add it as a string constant in the data section),
            //  instead copy the string to the memory occupied by tge byte array itself
            if (rightSideExpressionType.BaseType is StringLiteralTypeDef && leftSideExpressionType.IsArray)
            {
                string stringLiteral = ((StringLiteralTypeDef)rightSideExpressionType.BaseType).Value;

                if (rightSideExpressionType.ArrayLength > leftSideExpressionType.ArrayLength)
                {
                    throw new Exception("The string '" + stringLiteral + "' is too large to be assigned by value to the left hand expression.");
                }

                //Put start address to copy string value to into eax
                ((IHasAddress)Tokens[0]).PushAddress(context);
                context.EmitInstruction(new IRPop()
                {
                    To = "eax"
                });

                for (int i = 0; i < leftSideExpressionType.ArrayLength; i++)
                {
                    byte charValue = i < stringLiteral.Length ? (byte)stringLiteral[i] : (byte)0;

                    //Put char value into ebx
                    context.EmitInstruction(new IRMoveImmediate()
                    {
                        To = "ebx", Value = new ImmediateValue(charValue), OperandSize = 1
                    });
                    //Store char value into address [eax + char offset]
                    context.EmitInstruction(new IRStoreRegisterPlusImmediate()
                    {
                        To = "eax", Offset = new ImmediateValue(i), From = "ebx", OperandSize = 1
                    });
                }
            }
            else
            {
                //right hand side value -> stack
                ((ICodeEmitter)Tokens[2]).Emit(context);

                if (rightSideExpressionType.GetSize() > 4)
                {
                    //[sp] -> [destination]
                    //Dest address -> eax
                    ((IHasAddress)Tokens[0]).PushAddress(context);
                    context.EmitInstruction(new IRPop()
                    {
                        To = "eax"
                    });

                    //sp -= size of value
                    context.EmitInstruction(new IRMoveImmediate()
                    {
                        To = "ebx", Value = new ImmediateValue(rightSideExpressionType.GetSize())
                    });
                    context.EmitInstruction(new IRSub()
                    {
                        Left = "sp", Right = "ebx", To = "sp"
                    });

                    context.EmitInstruction(new IRMemCopy()
                    {
                        From = "sp", To = "eax", Length = new ImmediateValue(rightSideExpressionType.GetSize())
                    });
                }
                else
                {
                    //store ebx -> [destination]
                    ((IHasAddress)Tokens[0]).PushAddress(context);
                    context.EmitInstruction(new IRPop()
                    {
                        To = "eax"
                    });

                    //Store assign value in ebx
                    context.EmitInstruction(new IRPop()
                    {
                        To = "ebx"
                    });
                    context.EmitInstruction(new IRStoreRegister()
                    {
                        From = "ebx", To = "eax", OperandSize = rightSideExpressionType.GetSize()
                    });                                                                                                                           //MB!
                }
            }
        }
Esempio n. 6
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);
            }
        }