// Concatenate two literal strings ParseNode OptimiseConcatenation(ParseNode node) { BinaryOpParseNode tokenNode = (BinaryOpParseNode)node; tokenNode.Left = OptimiseExpressionTree(tokenNode.Left); tokenNode.Right = OptimiseExpressionTree(tokenNode.Right); if ((tokenNode.Left.ID == ParseID.STRING) && (tokenNode.Right.ID == ParseID.STRING)) { StringParseNode op1 = (StringParseNode)tokenNode.Left; StringParseNode op2 = (StringParseNode)tokenNode.Right; node = new StringParseNode(op1.Value + op2.Value); } return node; }
/// <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"); }
// Block IF ParseNode KBlockIf(ParseNode expr) { ConditionalParseNode node = new ConditionalParseNode(); TokenID id; do { ParseNode labelNode; CollectionParseNode statements = new CollectionParseNode(); SimpleToken token = _ls.GetKeyword(); ++_blockDepth; while (!IsEndOfIfBlock(token.ID)) { labelNode = CheckLabel(); if (labelNode != null) { statements.Add(labelNode); } ParseNode subnode = Statement(token); if (subnode != null) { statements.Add(MarkLine()); statements.Add(subnode); } ExpectEndOfLine(); token = _ls.GetKeyword(); } --_blockDepth; // Labels on terminators are valid so we need // to check for and add those. labelNode = CheckLabel(); if (labelNode != null) { statements.Add(labelNode); } node.Add(expr, statements); id = token.ID; if (id == TokenID.KELSEIF) { ExpectToken(TokenID.LPAREN); expr = Expression(); ExpectToken(TokenID.RPAREN); ExpectToken(TokenID.KTHEN); ExpectEndOfLine(); } else if (id == TokenID.KELSE) { // We mark the end of the sequence of IF blocks with // a null expression. expr = null; ExpectEndOfLine(); } } while(id == TokenID.KELSEIF || id == TokenID.KELSE); _ls.BackToken(); ExpectToken(TokenID.KENDIF); return node; }
// Given two parse nodes with types associated, this function returns the // largest type required for a consistent arithmetic operation between them. SymType TypePromotion(ParseNode p1, ParseNode p2) { return Symbol.LargestType(p1.Type, p2.Type); }
/// <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); } } }
// Add this node to list of initialisation nodes that are // executed when the method is loaded. void AddInit(ParseNode initNode) { Debug.Assert(_initList != null); _initList.Add(initNode); }
/// <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); } } }
/// <summary> /// Retrieve the label value of a SymbolParseNode. /// </summary> /// <param name="node">A Label parse node</param> /// <returns>A symbol entry representing the label</returns> public Symbol GetLabel(ParseNode node) { if (node == null) { return null; } Debug.Assert(node is SymbolParseNode); SymbolParseNode identNode = (SymbolParseNode)node; return identNode.Symbol; }
// Optimise a negation expression where both nodes are literal // values. Substitute the node with the result of the negation. ParseNode OptimiseMinus(ParseNode node) { UnaryOpParseNode tokenNode = (UnaryOpParseNode)node; tokenNode.Operand = OptimiseExpressionTree(tokenNode.Operand); if (tokenNode.Operand.IsNumber) { NumberParseNode op1 = (NumberParseNode)tokenNode.Operand; node = new NumberParseNode(-op1.Value); } return node; }
// Optimise a subtraction expression where both nodes are literal // values. Substitute the node with the result of the subtraction. ParseNode OptimiseSubtraction(ParseNode node) { BinaryOpParseNode tokenNode = (BinaryOpParseNode)node; tokenNode.Left = OptimiseExpressionTree(tokenNode.Left); tokenNode.Right = OptimiseExpressionTree(tokenNode.Right); if (tokenNode.IsNumber) { NumberParseNode op1 = (NumberParseNode)tokenNode.Left; NumberParseNode op2 = (NumberParseNode)tokenNode.Right; node = new NumberParseNode(op1.Value - op2.Value); } // Check for zero simplification if (tokenNode.Right.IsNumber) { if (tokenNode.Right.Value.IsZero) { return tokenNode.Left; } } return node; }
// Optimise the parse tree generated by parsing an expression in order to collapse // arithmetic operations with constant operands. ParseNode OptimiseExpressionTree(ParseNode node) { if (node != null) { switch (node.ID) { case ParseID.MINUS: return OptimiseMinus(node); case ParseID.ADD: return OptimiseAddition(node); case ParseID.MULT: return OptimiseMultiplication(node); case ParseID.DIVIDE: return OptimiseDivision(node); case ParseID.SUB: return OptimiseSubtraction(node); case ParseID.EXP: return OptimiseExponentation(node); case ParseID.CONCAT: return OptimiseConcatenation(node); } } return node; }
// Optimise an exponentation expression where both nodes are literal // values. Substitute the node with the result of the exponentation. ParseNode OptimiseExponentation(ParseNode node) { BinaryOpParseNode tokenNode = (BinaryOpParseNode)node; tokenNode.Left = OptimiseExpressionTree(tokenNode.Left); tokenNode.Right = OptimiseExpressionTree(tokenNode.Right); if (tokenNode.IsNumber) { NumberParseNode op1 = (NumberParseNode)tokenNode.Left; NumberParseNode op2 = (NumberParseNode)tokenNode.Right; node = new NumberParseNode(op1.Value.Pow(op2.Value)); } // x raised to the powers of -1, 0 and 1 all yield constant expressions // so we can simplify that right now. if (tokenNode.Right.IsNumber) { Variant rightValue = tokenNode.Right.Value; if (rightValue.Compare(-1)) { BinaryOpParseNode divNode = new BinaryOpParseNode(ParseID.DIVIDE); divNode.Left = new NumberParseNode(new Variant(1)); divNode.Right = tokenNode.Left; divNode.Type = tokenNode.Left.Type; return divNode; } if (rightValue.IsZero) { return new NumberParseNode(1); } if (rightValue.Compare(1)) { return tokenNode.Left; } } return node; }
// Optimise a division expression where both nodes are literal // values. Substitute the node with the result of the division. ParseNode OptimiseDivision(ParseNode node) { BinaryOpParseNode tokenNode = (BinaryOpParseNode)node; tokenNode.Left = OptimiseExpressionTree(tokenNode.Left); tokenNode.Right = OptimiseExpressionTree(tokenNode.Right); if (tokenNode.IsNumber) { NumberParseNode op1 = (NumberParseNode)tokenNode.Left; NumberParseNode op2 = (NumberParseNode)tokenNode.Right; try { node = new NumberParseNode(op1.Value / op2.Value); } catch (DivideByZeroException) { _messages.Error(MessageCode.DIVISIONBYZERO, "Constant division by zero"); } } return node; }
/// <summary> /// Adds a case statement and target label. /// </summary> /// <param name="expr">Case expression node</param> /// <param name="label">Parsenode for the target label</param> public void Add(ParseNode expr, ParseNode label) { _caseList.Add(expr); _labelList.Add(label); }
// Scan the expression tree and adjust the node type to the type // determined by the arithmetic operation on its operators. void AdjustNodeType(ParseNode node) { if (node == null) { return; } switch (node.ID) { case ParseID.IDENT: { IdentifierParseNode identNode = (IdentifierParseNode)node; node.Type = identNode.Symbol.Type; break; } case ParseID.ADD: case ParseID.SUB: case ParseID.MULT: case ParseID.EXP: case ParseID.DIVIDE: { BinaryOpParseNode tokenNode = (BinaryOpParseNode)node; AdjustNodeType(tokenNode.Left); AdjustNodeType(tokenNode.Right); SymType type1 = tokenNode.Left.Type; SymType type2 = tokenNode.Right.Type; node.Type = Symbol.LargestType(type1, type2); break; } } }
/// <summary> /// Generate code for an expression tree. /// </summary> /// <param name="typeNeeded">The type to which the expression should be converted if it /// does not evaluate to that type natively.</param> /// <param name="rootNode">The ParseNode of the root of the expression tree.</param> /// <returns>The type of the generated expression</returns> public SymType GenerateExpression(SymType typeNeeded, ParseNode rootNode) { if (rootNode == null) { throw new ArgumentNullException("rootNode"); } SymType thisType = rootNode.Generate(this, SymType.GENERIC); return _em.ConvertType(thisType, typeNeeded); }
/// <summary> /// Adds the given parameter to this set of parameters. /// </summary> /// <param name="node">The Parsenode to add</param> public void Add(ParseNode node) { if (node == null) { throw new ArgumentNullException("node"); } Add(node, false); }
/// <summary> /// Adds the given parsenode as a child of this token node. /// </summary> /// <param name="node">The Parsenode to add</param> public void Add(ParseNode node) { Nodes.Add(node); }
/// <summary> /// Adds the given parameter to this set of parameters and specify how the /// parameter should be passed to the function. /// </summary> /// <param name="node">The Parsenode to add</param> /// <param name="useByRef">Whether the parameter should be passed by value or reference</param> public void Add(ParseNode node, bool useByRef) { if (node == null) { throw new ArgumentNullException("node"); } ParameterParseNode paramNode = new ParameterParseNode(node); paramNode.Type = node.Type; paramNode.IsByRef = useByRef; Nodes.Add(paramNode); }
/// <summary> /// Adds a conditional and body. /// </summary> /// <param name="expr">Conditional expression node</param> /// <param name="body">Statements to be executed</param> public void Add(ParseNode expr, CollectionParseNode body) { _exprList.Add(expr); _bodyList.Add(body); }
/// <summary> /// Adds the given parameter to this set of parameters. /// </summary> /// <param name="node">The Parsenode to add</param> /// <param name="symbol">The symbol associated with the parameter</param> public void Add(ParseNode node, Symbol symbol) { if (node == null) { throw new ArgumentNullException("node"); } ParameterParseNode paramNode = new ParameterParseNode(node, symbol); paramNode.Type = node.Type; Nodes.Add(paramNode); }
// Arithmetic IF ParseNode KArithmeticIf(ParseNode expr) { ArithmeticConditionalParseNode node = new ArithmeticConditionalParseNode(); node.ValueExpression = expr; node.Add(ParseLabel()); ExpectToken(TokenID.COMMA); node.Add(ParseLabel()); ExpectToken(TokenID.COMMA); node.Add(ParseLabel()); return node; }
/// <summary> /// Creates a subroutine or function parameters parse node. /// </summary> /// <param name="paramNode">A ParseNode object that contains the parameter value</param> public ParameterParseNode(ParseNode paramNode) { _paramNode = paramNode; }
// Logical IF ParseNode KLogicalIf(ParseNode expr) { ConditionalParseNode node = new ConditionalParseNode(); _parsingIf = true; CollectionParseNode body = new CollectionParseNode(); body.Add(Statement(_ls.GetKeyword())); _parsingIf = false; node.Add(expr, body); return node; }
/// <summary> /// Creates a subroutine or function parameters parse node using the /// given symbol as the parameter type. /// </summary> /// <param name="paramNode">A ParseNode object that contains the parameter value</param> /// <param name="symbol">A Symbol table item that represents the parameter name</param> public ParameterParseNode(ParseNode paramNode, Symbol symbol) { _paramNode = paramNode; _symbol = symbol; }
/// <summary> /// Generate and return an XmlDocument that represents the /// parse tree from the given root node down. /// </summary> /// <param name="rootNode">Parse tree root node</param> /// <returns>The XmlDocument for the root node</returns> public static XmlDocument Tree(ParseNode rootNode) { XmlDocument doc = new XmlDocument(); XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null); doc.AppendChild(docNode); rootNode.Dump(new ParseNodeXML(doc, "Root")); return doc; }
// Return whether the node is a possible complex part bool IsComplexPart(ParseNode node) { return node.ID == ParseID.NUMBER && (node.Type == SymType.INTEGER || node.Type == SymType.FLOAT); }