/// <summary> /// Emit this code to load a null value to the stack. /// </summary> /// <param name="cg">A CodeGenerator object</param> /// <param name="returnType">The type required by the caller</param> /// <returns>The symbol type of the value generated</returns> public override SymType Generate(CodeGenerator cg, SymType returnType) { if (cg == null) { throw new ArgumentNullException("cg"); } cg.Emitter.LoadNull(); return Type; }
/// <summary> /// Emit the code to create an array of variable arguments and evaluate /// and store each argument in the array. On exit, the address of the /// array is left on the top of the stack. /// </summary> /// <param name="cg">A CodeGenerator object</param> /// <param name="returnType">The type required by the caller</param> /// <returns>The symbol type of the value generated</returns> public override SymType Generate(CodeGenerator cg, SymType returnType) { if (cg == null) { throw new ArgumentNullException("cg"); } int argCount = Nodes.Count; cg.Emitter.CreateSimpleArray(argCount, typeof(Object)); for (int c = 0; c < argCount; ++c) { cg.Emitter.Dup(); cg.Emitter.LoadInteger(c); cg.Emitter.StoreElementReference(cg.GenerateExpression(SymType.NONE, Nodes[c])); } return SymType.VARARG; }
// Generate the code for a string concatenation operator SymType GenerateConcat(CodeGenerator cg) { Type charType = Symbol.SymTypeToSystemType(Left.Type); cg.GenerateExpression(Left.Type, Left); cg.GenerateExpression(Left.Type, Right); cg.Emitter.Call(cg.GetMethodForType(charType, "Concat", new [] { charType, charType })); return Left.Type; }
/// <summary> /// Generate the code to push one parameter onto the caller stack. There are /// three different approaches here: /// /// 1. Passing a defined variable. We either pass the address of the /// variable (which may be local, parameter or static) if the corresponding /// argument is BYREF, or we pass the value. /// 2. Passing a computed value. A computed value has no storage so if the /// corresponding argument is BYREF, we need to allocate storage for it /// and pass the address of the storage. /// 3. Finally, a computed value where the argument is BYVAL is passed on /// the stack. /// /// </summary> /// <param name="cg">A CodeGenerator object</param> /// <param name="symParam">Symbol entry for the called function</param> /// <param name="locals">A Temporaries collection for any local temporaries</param> /// <returns>The system type corresponding to this parameter.</returns> public Type Generate(CodeGenerator cg, Symbol symParam, Temporaries locals) { if (cg == null) { throw new ArgumentNullException("cg"); } if (locals == null) { throw new ArgumentNullException("locals"); } // Set some flags up-front bool isByRef = (symParam != null) ? symParam.IsByRef : IsByRef; bool isArray = (symParam != null) && symParam.IsArray; // The argument is an array, so the source must either be an array or // an array reference. if (isArray && _paramNode.ID == ParseID.IDENT) { IdentifierParseNode identNode = (IdentifierParseNode)_paramNode; Symbol symIdent = identNode.Symbol; if (symIdent.IsArray) { GenerateLoadSubArray(cg, identNode, symParam, locals); return symIdent.SystemType; } } // Parameter is an identifier. If passing by reference, pass the address // of the identifier in the local context. Otherwise extract and pass the // value. if (_paramNode.ID == ParseID.IDENT) { IdentifierParseNode identNode = (IdentifierParseNode)_paramNode; SymType identType = identNode.Type; Symbol symIdent = identNode.Symbol; if (!symIdent.IsInline && !identNode.HasSubstring) { // If we're passing an existing parameter, it is already // a reference so don't double it up. if (symIdent.IsParameter) { cg.Emitter.LoadParameter(symIdent.ParameterIndex); if (!isByRef && symIdent.IsValueType) { cg.Emitter.LoadIndirect(identType); } } else { if (symIdent.IsArray && !identNode.HasIndexes) { cg.GenerateLoadArray(identNode, false); return symIdent.SystemType; } if (isByRef) { cg.LoadAddress(identNode); } else { identNode.Generate(cg); if (symParam != null) { if (!symParam.IsMethod) { cg.Emitter.ConvertType(identNode.Type, symParam.Type); } identType = symParam.Type; } } } Type paramType = Symbol.SymTypeToSystemType(identType); if (isByRef) { paramType = paramType.MakeByRefType(); } return paramType; } } // For reference function parameters, if this argument is not an // addressable object, such as a literal value or an expression, // then we need to generate local storage for the result and pass // the address of that. if (isByRef) { LocalDescriptor index = locals.New(_paramNode.Type); SymType exprType = cg.GenerateExpression(_paramNode.Type, _paramNode); cg.Emitter.StoreLocal(index); cg.Emitter.LoadLocalAddress(index); return Symbol.SymTypeToSystemType(exprType).MakeByRefType(); } // Byval argument passing SymType neededType = (symParam != null) ? symParam.Type : Type; SymType thisType = cg.GenerateExpression(neededType, _paramNode); if (symParam != null) { thisType = symParam.Type; } return Symbol.SymTypeToSystemType(thisType); }
/// <summary> /// Emit this code to load the value to the stack. /// </summary> /// <param name="cg">A CodeGenerator object</param> /// <param name="returnType">The type required by the caller</param> /// <returns>The symbol type of the value generated</returns> public override SymType Generate(CodeGenerator cg, SymType returnType) { if (cg == null) { throw new ArgumentNullException("cg"); } switch (ID) { case ParseID.ADD: return GenerateAdd(cg); case ParseID.EQV: return GenerateEq(cg); case ParseID.NEQV: return GenerateNe(cg); case ParseID.XOR: return GenerateXor(cg); case ParseID.OR: return GenerateOr(cg); case ParseID.AND: return GenerateAnd(cg); case ParseID.GT: return GenerateGt(cg); case ParseID.GE: return GenerateGe(cg); case ParseID.LE: return GenerateLe(cg); case ParseID.EQ: return GenerateEq(cg); case ParseID.NE: return GenerateNe(cg); case ParseID.LT: return GenerateLt(cg); case ParseID.SUB: return GenerateSub(cg); case ParseID.MULT: return GenerateMult(cg); case ParseID.DIVIDE: return GenerateDivide(cg); case ParseID.CONCAT: return GenerateConcat(cg); case ParseID.EXP: return GenerateExp(cg); } Debug.Assert(false, "Unsupported parse ID for BinaryOpParseNode"); return Value.Type; }
/// <summary> /// Emit this code to load the value to the stack. /// </summary> /// <param name="cg">A CodeGenerator object</param> /// <param name="returnType">The type required by the caller</param> /// <returns>The symbol type of the value generated</returns> public override SymType Generate(CodeGenerator cg, SymType returnType) { if (cg == null) { throw new ArgumentNullException("cg"); } cg.GenerateLoad(Value); return Value.Type; }
/// <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> /// <returns>A list of system types corresponding to the computed parameters.</returns> public new Type[] Generate(CodeGenerator cg) { if (cg == null) { throw new ArgumentNullException("cg"); } _locals = new Temporaries(cg.Emitter); Type [] paramTypes = new Type[Nodes.Count]; for (int c = 0; c < Nodes.Count; ++c) { ParameterParseNode paramNode = Nodes[c]; paramTypes[c] = paramNode.Generate(cg, _locals); } return paramTypes; }
// Generate the code for a logical Less Than operator SymType GenerateLt(CodeGenerator cg) { SymType neededType = TypePromotion(Left, Right); cg.GenerateExpression(neededType, Left); cg.GenerateExpression(neededType, Right); if (Symbol.IsCharType(neededType)) { Type charType = Symbol.SymTypeToSystemType(neededType); cg.Emitter.Call(cg.GetMethodForType(charType, "Compare", new [] {charType, charType})); cg.Emitter.LoadInteger(0); } cg.Emitter.CompareLesser(); return Type; }
// Generate the code for a binary subtraction operator SymType GenerateSub(CodeGenerator cg) { cg.GenerateExpression(Type, Left); cg.GenerateExpression(Type, Right); cg.Emitter.Sub(Type); return Type; }
/// <summary> /// Implements the base code generator for the node to invoke a /// function implementation with a parse node value. /// </summary> /// <param name="cg">The code generator object</param> /// <param name="node">A parse node supplied to the generator function</param> /// <returns>The computed type</returns> public virtual void Generate(CodeGenerator cg, ParseNode node) { throw new InvalidOperationException("ParseNode does not implement Generate"); }
/// <summary> /// Emit this code to load the value to the stack. /// </summary> /// <param name="cg">A CodeGenerator object</param> /// <param name="returnType">The type required by the caller</param> /// <returns>The symbol type of the value generated</returns> public override SymType Generate(CodeGenerator cg, SymType returnType) { if (cg == null) { throw new ArgumentNullException("cg"); } if (ID == ParseID.LABEL) { if (Symbol.IsFixedStatic) { cg.Emitter.LoadString(Symbol.Value.StringValue); return Type; } return cg.LoadLocal(Symbol); } Debug.Assert(false, "Unsupported parse ID for SymbolParseNode"); return Value.Type; }
/// <summary> /// Implements the base code generator for the node to invoke a /// function implementation with a symbol type. /// </summary> /// <param name="cg">The code generator object</param> /// <param name="returnType">The expected type of the return value</param> /// <returns>The computed type</returns> public override SymType Generate(CodeGenerator cg, SymType returnType) { if (cg == null) { throw new ArgumentNullException("cg"); } cg.Emitter.LoadLocal(_local); return Symbol.SystemTypeToSymbolType(_local.Type); }
/// <summary> /// Implements the base code generator for the node to invoke a /// function implementation with a symbol type. /// </summary> /// <param name="cg">The code generator object</param> /// <param name="returnType">The expected type of the return value</param> /// <returns>The computed type</returns> public virtual SymType Generate(CodeGenerator cg, SymType returnType) { throw new InvalidOperationException("ParseNode does not implement Generate"); }
/// <summary> /// Emit the code to call an external function complete with /// parameters. /// </summary> /// <param name="cg">A code generator object</param> /// <param name="returnType">The expected return type</param> /// <returns>The actual return type from the function</returns> public override SymType Generate(CodeGenerator cg, SymType returnType) { System.Type argType = typeof(void); System.Type [] paramTypes; if (Parameters != null) { paramTypes = Parameters.Generate(cg); if (paramTypes.Length > 0) { argType = paramTypes[0]; } } else { paramTypes = System.Type.EmptyTypes; } // For anything else, we emit the appropriate call to the library. If // inline is permitted, we check the library for an inline version of the // name and if one exists, invoke it to insert the inline code. MethodInfo meth; if (Inline) { // First try specific methods where different inline methods are // provided depending on the type. meth = typeof(Inlined).GetMethod(Name, new [] { typeof(Emitter), typeof(System.Type) }); if (meth != null) { object [] ilParams = { cg.Emitter, argType }; meth.Invoke(null, ilParams); return Type; } // Otherwise try the type-less variant. meth = typeof(Inlined).GetMethod(Name, new [] { typeof(Emitter) }); if (meth != null) { object [] ilParams = { cg.Emitter }; meth.Invoke(null, ilParams); return Type; } } meth = cg.GetMethodForType(LibraryName, Name, paramTypes); cg.Emitter.Call(meth); // If this method returns a value but we're invoking it as a // subroutine, discard the return value from the stack if (returnType == SymType.NONE && meth.ReturnType != typeof(void)) { cg.Emitter.Pop(); } returnType = Symbol.SystemTypeToSymbolType(meth.ReturnType); if (Parameters != null) { Parameters.FreeLocalDescriptors(); } return returnType; }
/// <summary> /// Emit the code to call an external function complete with /// parameters. /// </summary> /// <param name="cg">A code generator object</param> public override void Generate(CodeGenerator cg) { Generate(cg, SymType.NONE); }
/// <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; }
// Generate the code for a binary division operator SymType GenerateDivide(CodeGenerator cg) { cg.GenerateExpression(Type, Left); cg.GenerateExpression(Type, Right); cg.Emitter.Div(Type); return Type; }
// Generate the code for a unary minus operator SymType GenerateMinus(CodeGenerator cg) { cg.GenerateExpression(Type, Operand); cg.Emitter.Neg(Type); return Type; }
// Generate the code for a binary exponentiation operator SymType GenerateExp(CodeGenerator cg) { cg.GenerateExpression(SymType.DOUBLE, Left); cg.GenerateExpression(SymType.DOUBLE, Right); cg.Emitter.Call(cg.GetMethodForType(typeof(Math), "Pow", new [] {typeof(double), typeof(double)})); return SymType.DOUBLE; }
// Generate the code for a unary NOT logical operator SymType GenerateNot(CodeGenerator cg) { cg.GenerateExpression(Type, Operand); cg.Emitter.LoadInteger(0); cg.Emitter.CompareEquals(); return Type; }
// Generate the code for a logical Not Equals operator SymType GenerateNe(CodeGenerator cg) { SymType neededType = TypePromotion(Left, Right); cg.GenerateExpression(neededType, Left); cg.GenerateExpression(neededType, Right); if (Symbol.IsCharType(neededType)) { Type charType = Symbol.SymTypeToSystemType(neededType); cg.Emitter.Call(cg.GetMethodForType(charType, "op_Equality", new [] {charType, charType})); } else { cg.Emitter.CompareEquals(); } cg.Emitter.LoadInteger(1); cg.Emitter.Xor(); return Type; }
// Generate the code to write an expression to a substring represented // by an identifier which should be fixed string type. void GenerateSaveSubstring(CodeGenerator cg, SymType charType) { Type baseType = Symbol.SymTypeToSystemType(charType); // Optimise for constant start/end values if (Identifier.SubstringStart.IsConstant) { int startIndex = Identifier.SubstringStart.Value.IntValue - 1; cg.Emitter.LoadInteger(startIndex); } else { cg.GenerateExpression(SymType.INTEGER, Identifier.SubstringStart); cg.Emitter.LoadInteger(1); cg.Emitter.Sub(SymType.INTEGER); } if (Identifier.SubstringEnd == null) { cg.Emitter.LoadInteger(Identifier.Symbol.FullType.Width); } else { if (Identifier.SubstringEnd.IsConstant) { int endIndex = Identifier.SubstringEnd.Value.IntValue - 1; cg.Emitter.LoadInteger(endIndex); } else { cg.GenerateExpression(SymType.INTEGER, Identifier.SubstringEnd); cg.Emitter.LoadInteger(1); cg.Emitter.Sub(SymType.INTEGER); } } cg.Emitter.Call(cg.GetMethodForType(typeof(JComLib.FixedString), "Set", new [] { baseType, typeof(int), typeof(int) })); }
// Generate the code for an exclusive OR operator SymType GenerateXor(CodeGenerator cg) { cg.GenerateExpression(Type, Left); cg.GenerateExpression(Type, Right); cg.Emitter.Xor(); return Type; }
// Emit the appropriate store parameter index opcode. void GenerateStoreArgument(CodeGenerator cg, Symbol sym) { switch (sym.Linkage) { case SymLinkage.BYVAL: cg.GenerateExpression(sym.Type, ValueExpression); cg.Emitter.StoreParameter(sym.ParameterIndex); break; case SymLinkage.BYREF: cg.Emitter.LoadParameter(sym.ParameterIndex); cg.GenerateExpression(sym.Type, ValueExpression); cg.Emitter.StoreIndirect(sym.Type); break; } }
/// <summary> /// Emit this code to load the value to the stack. /// </summary> /// <param name="cg">A CodeGenerator object</param> /// <param name="returnType">The type required by the caller</param> /// <returns>The symbol type of the value generated</returns> public override SymType Generate(CodeGenerator cg, SymType returnType) { if (cg == null) { throw new ArgumentNullException("cg"); } switch (ID) { case ParseID.MINUS: return GenerateMinus(cg); case ParseID.NOT: return GenerateNot(cg); } Debug.Assert(false, "Unsupported parse ID for UnaryOpParseNode"); return Value.Type; }
// Emit the code that loads part of an entire array by making a copy of // the array to the destination array dimensions and copying from the // given offset. void GenerateLoadSubArray(CodeGenerator cg, IdentifierParseNode identNode, Symbol symParam, Temporaries locals) { if (!identNode.HasIndexes) { cg.GenerateLoadArray(identNode, false); return; } LocalDescriptor index = locals.New(symParam.SystemType); cg.GenerateLoadArrayAddress(identNode); cg.Emitter.CreateSimpleArray(symParam.ArraySize, Symbol.SymTypeToSystemType(symParam.Type)); cg.Emitter.Dup(); cg.Emitter.StoreLocal(index); cg.Emitter.LoadInteger(0); cg.Emitter.LoadInteger(symParam.ArraySize); cg.Emitter.Call(typeof(Array).GetMethod("Copy", new [] { typeof(Array), typeof(int), typeof(Array), typeof(int), typeof(int) })); cg.Emitter.LoadLocal(index); }
// Emit code that saves the result of an expression to an array element. void GenerateSaveToArray(CodeGenerator cg) { Symbol sym = Identifier.Symbol; Debug.Assert(sym.IsArray); if (Identifier.IsArrayBase) { if (sym.IsParameter) { GenerateStoreArgument(cg, sym); } else { cg.GenerateExpression(SymType.NONE, ValueExpression); cg.Emitter.StoreLocal(sym.Index); } return; } cg.GenerateLoadArrayAddress(Identifier); if (Identifier.HasSubstring) { cg.Emitter.LoadArrayElement(sym); cg.GenerateExpression(SymType.FIXEDCHAR, ValueExpression); GenerateSaveSubstring(cg, SymType.FIXEDCHAR); return; } if (sym.Type == SymType.FIXEDCHAR) { cg.Emitter.LoadArrayElement(sym); cg.GenerateExpression(SymType.NONE, ValueExpression); cg.Emitter.Call(cg.GetMethodForType(typeof(JComLib.FixedString), "Set", new[] { Symbol.SymTypeToSystemType(ValueExpression.Type) })); return; } cg.GenerateExpression(sym.Type, ValueExpression); cg.Emitter.StoreArrayElement(sym); }
/// <summary> /// Convert the parse tree to executable code and then execute the /// resulting code. The return value from the specified entry point function /// is returned as an object. /// </summary> /// <param name="entryPointName">The name of the method to be called</param> /// <returns>An ExecutionResult object representing the result of the execution</returns> public ExecutionResult Execute(string entryPointName) { CodeGenerator codegen = new CodeGenerator(_opts); MarkExecutable(); codegen.GenerateCode(_programDef); return codegen.Run(entryPointName); }
/// <summary> /// Emit the code to generate the assignment of an expression /// to an identifier. Various forms are permitted: /// /// identifier = value /// identifier(array_indexes) = value /// array = another_array /// identifier(substring) = value /// /// </summary> /// <param name="cg">A code generator object</param> public override void Generate(CodeGenerator cg) { if (cg == null) { throw new ArgumentNullException("cg"); } Symbol sym = Identifier.Symbol; if (sym.IsArray) { GenerateSaveToArray(cg); return; } if (Identifier.HasSubstring) { if (sym.IsParameter) { cg.Emitter.LoadParameter(sym.ParameterIndex); } else { cg.Emitter.LoadLocal(sym.Index); } SymType exprType = cg.GenerateExpression(SymType.NONE, ValueExpression); GenerateSaveSubstring(cg, exprType); return; } if (!sym.IsValueType) { if (sym.IsParameter) { cg.Emitter.LoadParameter(sym.ParameterIndex); } else { cg.Emitter.LoadLocal(sym.Index); } SymType exprType = cg.GenerateExpression(SymType.NONE, ValueExpression); if (sym.Type == SymType.FIXEDCHAR) { MethodInfo meth = cg.GetMethodForType(typeof(JComLib.FixedString), "Set", new [] { Symbol.SymTypeToSystemType(exprType) }); cg.Emitter.Call(meth); } return; } if (sym.IsLocal) { cg.GenerateExpression(sym.Type, ValueExpression); cg.StoreLocal(sym); return; } GenerateStoreArgument(cg, sym); }
/// <summary> /// Convert the parse tree to executable code then save it to the /// filename specified in the options. /// </summary> public void Save() { try { CodeGenerator codegen = new CodeGenerator(_opts); MarkExecutable(); codegen.GenerateCode(_programDef); codegen.Save(); } catch (CodeGeneratorException e) { _messages.Error(e.Filename, MessageCode.CODEGEN, e.Linenumber, e.Message); } }