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" }); } }
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); } }
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); } }