/// <summary> /// Generate the code to push the specified parameters onto the caller /// stack. Unless the called function or subroutine is being called /// indirectly (and thus we may not have knowledge of its parameter /// count or types), the number of parameters in the caller and callee /// must agree. /// </summary> /// <param name="cg">A CodeGenerator object</param> /// <param name="sym">Symbol entry for the called function</param> /// <returns>A list of system types corresponding to the computed parameters.</returns> public Type[] Generate(CodeGenerator cg, Symbol sym) { if (cg == null) { throw new ArgumentNullException("cg"); } if (sym == null) { throw new ArgumentNullException("sym"); } int callerParameterCount = Nodes.Count; int calleeParameterCount = (sym.Parameters != null) ? sym.Parameters.Count : 0; if (!sym.IsParameter && callerParameterCount != calleeParameterCount) { cg.Error(String.Format("Parameter count mismatch for {0}", sym.Name)); } _locals = new Temporaries(cg.Emitter); Type [] paramTypes = new Type[callerParameterCount]; for (int c = 0; c < Nodes.Count; ++c) { ParameterParseNode paramNode = Nodes[c]; Symbol symParam = (sym.Parameters != null) ? sym.Parameters[c] : null; paramTypes[c] = paramNode.Generate(cg, symParam, _locals); } return paramTypes; }
// Internal generation logic for a subroutine or function call. SymType InternalGenerate(CodeGenerator cg, SymClass callType, string callName) { Symbol sym = ProcName.Symbol; SymType thisType = SymType.NONE; if (!sym.Defined) { cg.Error(sym.RefLine, String.Format("Undefined {0} {1}", callName, sym.Name)); } if (sym.Class != callType) { cg.Error(sym.RefLine, String.Format("{0} is not a {1}", sym.Name, callName)); } Type[] paramTypes = Parameters.Generate(cg, sym); if (sym.IsParameter) { ProcName.Generate(cg); cg.Emitter.CallIndirect(sym.Type, paramTypes); thisType = sym.Type; } else { if (sym.Info != null) { Debug.Assert(sym.Info is MethodInfo); cg.Emitter.Call((MethodInfo)sym.Info); thisType = sym.Type; } } // Sanity check, make sure alternate return labels are only specified // for subroutines. if (AlternateReturnLabels.Count > 0 && sym.Class != SymClass.SUBROUTINE) { throw new CodeGeneratorException("Codegen error: Alternate return labels only permitted for subroutines"); } // Post-alternate return branching if (AlternateReturnLabels.Count > 0) { Label [] jumpTable = new Label[AlternateReturnLabels.Count]; for (int c = 0; c < AlternateReturnLabels.Count; ++c) { Symbol symLabel = AlternateReturnLabels[c]; jumpTable[c] = (Label)symLabel.Info; } cg.Emitter.LoadInteger(1); cg.Emitter.Sub(SymType.INTEGER); cg.Emitter.Switch(jumpTable); } Parameters.FreeLocalDescriptors(); return thisType; }
/// <summary> /// Generate the code to emit a procedure. /// </summary> /// <param name="cg">A CodeGenerator object</param> public override void Generate(CodeGenerator cg) { if (cg == null) { throw new ArgumentNullException("cg"); } Symbol retVal = cg.CurrentProcedure.ProcedureSymbol.RetVal; if (retVal != null) { if (ReturnExpression != null) { SymType thisType = cg.GenerateExpression(SymType.NONE, ReturnExpression); cg.Emitter.ConvertType(thisType, retVal.Type); } else { if (retVal.Index == null) { cg.Error(string.Format("Function {0} does not return a value", cg.CurrentProcedure.ProcedureSymbol.Name)); } cg.Emitter.LoadLocal(retVal.Index); } } else { // For alternate return, if the method is marked as supporting // them then it will be compiled as a function. So it must always // have a return value. A value of 0 means the default behaviour // (i.e. none of the labels specified are picked). if (cg.CurrentProcedure.AlternateReturnCount > 0) { if (ReturnExpression != null) { cg.GenerateExpression(SymType.INTEGER, ReturnExpression); } else { cg.Emitter.LoadInteger(0); } } } cg.Emitter.Return(); }