Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        // 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) }));
        }
Ejemplo n.º 3
0
        // 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);
        }
Ejemplo n.º 4
0
 // 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;
 }
Ejemplo n.º 5
0
 // 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;
 }
Ejemplo n.º 6
0
        // 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;
        }
Ejemplo n.º 7
0
 // 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;
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Emit the code to generate a call to the READ library function.
        /// </summary>
        /// <param name="cg">A CodeGenerator object</param>
        public override void Generate(CodeGenerator cg)
        {
            if (cg == null) {
                throw new ArgumentNullException("cg");
            }

            Type readManagerType = typeof(JComLib.ReadManager);
            Type [] paramTypes = ReadManagerParamsNode.Generate(cg);

            cg.Emitter.CreateObject(readManagerType, paramTypes);
            LocalDescriptor objIndex = cg.Emitter.GetTemporary(readManagerType);
            cg.Emitter.StoreLocal(objIndex);

            if (EndLabel != null) {
                cg.Emitter.LoadLocal(objIndex);
                cg.Emitter.LoadInteger(1);
                cg.Emitter.Call(readManagerType.GetMethod("set_HasEnd", new [] { typeof(bool) }));
            }

            if (ErrLabel != null) {
                cg.Emitter.LoadLocal(objIndex);
                cg.Emitter.LoadInteger(1);
                cg.Emitter.Call(readManagerType.GetMethod("set_HasErr", new [] { typeof(bool) }));
            }

            LocalDescriptor index = cg.Emitter.GetTemporary(typeof(int));

            // Construct a parsenode that will be called for each item in the loop
            // including any implied DO loops.
            ReadItemParseNode itemNode = new ReadItemParseNode();
            itemNode.ReturnIndex = index;
            itemNode.ErrLabel = ErrLabel;
            itemNode.EndLabel = EndLabel;
            itemNode.ReadParamsNode = ReadParamsNode;
            itemNode.ReadManagerIndex = objIndex;

            if (ArgList != null && ArgList.Nodes.Count > 0) {
                int countOfArgs = ArgList.Nodes.Count;

                for (int c = 0; c < countOfArgs; ++c) {
                    itemNode.Generate(cg, ArgList.Nodes[c]);
                    ReadParamsNode.FreeLocalDescriptors();
                }
            } else {
                itemNode.Generate(cg, null);
            }

            // Issue an EndRecord to complete this record read
            cg.Emitter.LoadLocal(objIndex);
            cg.Emitter.Call(cg.GetMethodForType(readManagerType, "EndRecord", System.Type.EmptyTypes));

            cg.Emitter.ReleaseTemporary(index);
            cg.Emitter.ReleaseTemporary(objIndex);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Implements the code to initialise the array.
        /// </summary>
        /// <param name="cg">The code generator object</param>
        public override void Generate(CodeGenerator cg)
        {
            if (cg == null) {
                throw new ArgumentNullException("cg");
            }
            Symbol sym = Identifier.Symbol;

            // Simple array initialisation - just initialise the
            // specified element. More complex initialisation requires
            // a loop across the elements.
            Debug.Assert(sym.IsArray);
            if (Identifier.Indexes != null && Identifier.Indexes.Count > 0) {
                if (Identifier.Indexes.Count == 1) {
                    NumberParseNode number = (NumberParseNode)Identifier.Indexes[0];
                    Debug.Assert(sym.Dimensions[0].LowerBound.IsConstant);
                    int index = number.Value.IntValue + (0 - sym.Dimensions[0].LowerBound.Value.IntValue);
                    GenerateStoreToArray(cg, sym, index, RangeValue);
                } else {
                    Type [] paramTypes = new Type[Identifier.Indexes.Count + 1];
                    int index = 0;

                    cg.LoadLocal(sym);
                    while (index < Identifier.Indexes.Count) {
                        NumberParseNode number = (NumberParseNode)Identifier.Indexes[index];
                        Debug.Assert(sym.Dimensions[index].LowerBound.IsConstant);
                        cg.Emitter.LoadInteger(number.Value.IntValue + (0 - sym.Dimensions[index].LowerBound.Value.IntValue));
                        paramTypes[index++] = typeof(Int32);
                    }
                    cg.GenerateLoad(RangeValue);
                    paramTypes[index] = Symbol.SymTypeToSystemType(RangeValue.Type);

                    cg.Emitter.Call(cg.GetMethodForType(sym.SystemType, "Set", paramTypes));
                }
            }
            else if (StartRange < EndRange + 4) {

                // When initialising arrays less than 4 values, unroll
                // the loop as it will be faster.
                int index = StartRange;
                while (index <= EndRange) {
                    GenerateStoreToArray(cg, sym, index++, RangeValue);
                }
            } else {

                // For large arrays, generate code to initialise the elements
                // to a specific value.
                Label label1 = cg.Emitter.CreateLabel();
                cg.Emitter.LoadInteger(StartRange);
                LocalDescriptor tempIndex = cg.Emitter.GetTemporary(typeof(int));
                cg.Emitter.StoreLocal(tempIndex);
                cg.Emitter.MarkLabel(label1);
                GenerateStoreToArray(cg, sym, tempIndex.Index, RangeValue);
                cg.Emitter.LoadLocal(tempIndex);
                cg.Emitter.LoadInteger(1);
                cg.Emitter.Add(SymType.INTEGER);
                cg.Emitter.Dup();
                cg.Emitter.StoreLocal(tempIndex);
                cg.Emitter.LoadInteger(EndRange);
                cg.Emitter.BranchLessOrEqual(label1);
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Emit the code to generate a call to the READ library function. A
        /// parse node must be provided which evaluates to the address of the
        /// identifier into which the data is read.
        /// </summary>
        /// <param name="cg">A CodeGenerator object</param>
        /// <param name="node">A parse node for the READ identifier</param>
        public override void Generate(CodeGenerator cg, ParseNode node)
        {
            if (cg == null) {
                throw new ArgumentNullException("cg");
            }
            if (node is LoopParseNode) {
                LoopParseNode loopNode = (LoopParseNode)node;
                loopNode.Callback = this;
                loopNode.Generate(cg);
            } else {
                Type readManagerType = typeof(JComLib.ReadManager);
                List<Type> readParamTypes = new List<Type>();

                cg.Emitter.LoadLocal(ReadManagerIndex);
                readParamTypes.Add(readManagerType);

                readParamTypes.AddRange(ReadParamsNode.Generate(cg));

                if (node is IdentifierParseNode) {
                    IdentifierParseNode identNode = (IdentifierParseNode)node;
                    if (identNode.IsArrayBase) {
                        cg.Emitter.LoadInteger(identNode.Symbol.ArraySize);
                        identNode.Generate(cg);

                        readParamTypes.Add(typeof(int));
                        readParamTypes.Add(Symbol.SymTypeToSystemType(identNode.Symbol.Type).MakeArrayType());
                    } else if (identNode.HasSubstring) {
                        cg.GenerateExpression(SymType.INTEGER, identNode.SubstringStart);
                        if (identNode.SubstringEnd != null) {
                            cg.GenerateExpression(SymType.INTEGER, identNode.SubstringEnd);
                        } else {
                            cg.Emitter.LoadInteger(-1);
                        }
                        cg.LoadAddress(identNode);
                        readParamTypes.Add(typeof(int));
                        readParamTypes.Add(typeof(int));
                        readParamTypes.Add(Symbol.SymTypeToSystemType(identNode.Symbol.Type).MakeByRefType());
                    } else {
                        cg.LoadAddress(identNode);
                        readParamTypes.Add(Symbol.SymTypeToSystemType(identNode.Symbol.Type).MakeByRefType());
                    }
                }

                cg.Emitter.Call(cg.GetMethodForType(_libraryName, _name, readParamTypes.ToArray()));
                cg.Emitter.StoreLocal(ReturnIndex);

                if (EndLabel != null) {
                    cg.Emitter.LoadLocal(ReturnIndex);
                    cg.Emitter.LoadInteger(0);
                    cg.Emitter.BranchEqual((Label)EndLabel.Symbol.Info);
                }
                if (ErrLabel != null) {
                    cg.Emitter.LoadLocal(ReturnIndex);
                    cg.Emitter.LoadInteger(-1);
                    cg.Emitter.BranchEqual((Label)ErrLabel.Symbol.Info);
                }
            }
        }
Ejemplo n.º 11
0
        /// <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;
        }
Ejemplo n.º 12
0
        // Generate the code to extract a substring from the character string
        // at the top of the stack.
        SymType GenerateLoadSubstring(CodeGenerator cg)
        {
            Type charType = Symbol.SymTypeToSystemType(Type);

            cg.GenerateExpression(SymType.INTEGER, SubstringStart);
            cg.Emitter.LoadInteger(1);
            cg.Emitter.Sub(SymType.INTEGER);
            if (SubstringEnd == null) {
                cg.Emitter.Call(cg.GetMethodForType(charType, "Substring", new [] { typeof(int) }));
            } else {
                cg.Emitter.Dup();
                cg.GenerateExpression(SymType.INTEGER, SubstringEnd);
                cg.Emitter.Sub(SymType.INTEGER);
                cg.Emitter.Neg(SymType.INTEGER);
                cg.Emitter.Call(cg.GetMethodForType(charType, "Substring", new [] { typeof(int), typeof(int) }));
            }
            return Type;
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Emit the code to generate a call to the WRITE library function.
        /// 
        /// The WRITE function may be invoked as either a subroutine or a function depending
        /// on whether it is being used for formatting a string or writing to a device. The
        /// returnType parameter should direct how it should be used. If returnType is
        /// SymType.NONE then a subroutine call is being made and the return value will
        /// also be SymType.NONE and the stack will be cleared of any value returned from
        /// the function. If the returnType is not SymType.NONE then the return value is the
        /// type of the value on the top of the stack.
        /// </summary>
        /// <param name="cg">A CodeGenerator object</param>
        /// <param name="returnType">The expected type of the returned value</param>
        /// <returns>The type of the value on the stack or SymType.NONE</returns>
        public override SymType Generate(CodeGenerator cg, SymType returnType)
        {
            if (cg == null) {
                throw new ArgumentNullException("cg");
            }

            Type writeManagerType = typeof(JComLib.WriteManager);
            Type [] paramTypes = WriteManagerParamsNode.Generate(cg);

            cg.Emitter.CreateObject(writeManagerType, paramTypes);
            LocalDescriptor objIndex = cg.Emitter.GetTemporary(writeManagerType);
            cg.Emitter.StoreLocal(objIndex);

            if (ErrLabel != null) {
                cg.Emitter.LoadLocal(objIndex);
                cg.Emitter.LoadInteger(1);
                cg.Emitter.Call(writeManagerType.GetMethod("set_HasErr", new [] { typeof(bool) }));
            }

            if (FirstColumnSpecial) {
                cg.Emitter.LoadLocal(objIndex);
                cg.Emitter.LoadInteger(1);
                cg.Emitter.Call(writeManagerType.GetMethod("SetFirstColumnSpecial", new [] { typeof(bool) }));
            }

            LocalDescriptor index = cg.Emitter.GetTemporary(typeof(int));

            // Construct a parsenode that will be called for each item in the loop
            // including any implied DO loops.
            WriteItemParseNode itemNode = new WriteItemParseNode();
            itemNode.ReturnIndex = index;
            itemNode.ErrLabel = ErrLabel;
            itemNode.WriteParamsNode = WriteParamsNode;
            itemNode.WriteManagerIndex = objIndex;

            if (ArgList != null && ArgList.Nodes.Count > 0) {
                int countOfArgs = ArgList.Nodes.Count;
                for (int c = 0; c < countOfArgs; ++c) {
                    itemNode.Generate(cg, ArgList.Nodes[c]);
                    WriteParamsNode.FreeLocalDescriptors();
                }
            } else {
                itemNode.Generate(cg, null);
            }

            // Issue an EndRecord to complete this record write
            cg.Emitter.LoadLocal(objIndex);
            cg.Emitter.Call(cg.GetMethodForType(writeManagerType, "EndRecord", System.Type.EmptyTypes));

            // Discard the return value from the stack if we don't need it.
            if (returnType == SymType.NONE) {
                cg.Emitter.Pop();
            }

            cg.Emitter.ReleaseTemporary(index);
            cg.Emitter.ReleaseTemporary(objIndex);
            return SymType.CHAR;
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Emit the code to generate a call to the write library function. A
        /// parse node must be specified which evaluates to the value to be
        /// written.
        /// </summary>
        /// <param name="cg">A CodeGenerator object</param>
        /// <param name="node">A parse node for the WRITE identifier</param>
        public override void Generate(CodeGenerator cg, ParseNode node)
        {
            if (cg == null) {
                throw new ArgumentNullException("cg");
            }
            if (node is LoopParseNode) {
                LoopParseNode loopNode = (LoopParseNode)node;
                loopNode.Callback = this;
                loopNode.Generate(cg);
            } else {
                Type writeManagerType = typeof(JComLib.WriteManager);
                List<Type> writeParamTypes = new List<Type>();

                cg.Emitter.LoadLocal(WriteManagerIndex);
                writeParamTypes.Add(writeManagerType);

                if (WriteParamsNode != null) {
                    writeParamTypes.AddRange(WriteParamsNode.Generate(cg));
                }

                if (node != null) {
                    ParameterParseNode exprParam = new ParameterParseNode(node);
                    writeParamTypes.Add(exprParam.Generate(cg));
                }

                cg.Emitter.Call(cg.GetMethodForType(_libraryName, _name, writeParamTypes.ToArray()));
                cg.Emitter.StoreLocal(ReturnIndex);

                if (ErrLabel != null) {
                    cg.Emitter.LoadLocal(ReturnIndex);
                    cg.Emitter.LoadInteger(-1);
                    cg.Emitter.BranchEqual((Label)ErrLabel.Symbol.Info);
                }
            }
        }