示例#1
0
        }                                                          // set during AST construction

        #region implemented abstract members of Node

        public static OperatorNode BuildUnaryOperator(int level, string op, ExpressionNode arg)
        {
            var opNode = new OperatorNode();
            var args   = new LinkedList <ExpressionNode>();

            args.AddLast(arg);
            opNode.Arguments = args;
            opNode.Operator  = OperatorTypeHelper.GetOperatorType(level, op);
            return(opNode);
        }
        /// <summary>
        /// Parse one line expression with unary prefix operators. Operators must be given in reversed order. Enumerator must be
        /// positioned before first operator.
        /// </summary>
        /// <returns>Expression precedes with given operators.</returns>
        public static ExpressionNode AddPrefixOperators <TSymbol>(int opLevel, ExpressionNode expr, IEnumerator <IParseTree <TSymbol> > operators)
            where TSymbol : ISymbol <TSymbol>
        {
            ExpressionNode lastNode = expr;

            while (operators.MoveNext())
            {
                string opText = operators.Current.Fragment.GetOriginText();
                lastNode = OperatorNode.BuildUnaryOperator(opLevel, opText, lastNode);
            }
            return(lastNode);
        }
        /// <summary>
        /// Parse one line expression with opLevel-expressions and binary operators (from one level above) between them.
        /// If you want to parse leftToRight operator - provide enumerator with reversed order of arguments.
        /// </summary>
        public static ExpressionNode ParseBinOperator <TSymbol>(IEnumerator <IParseTree <TSymbol> > opExpr, int opLevel, bool leftToRight)
            where TSymbol : ISymbol <TSymbol>
        {
            var leftArg = ResolveOperatorExpression(opExpr.Current, opLevel);

            if (opExpr.MoveNext())   // this is not the last symbol
            // build recursively binary operator for this arg and the rest
            // get an operator
            {
                string opText = opExpr.Current.Fragment.GetOriginText();
                Debug.Assert(opExpr.MoveNext());
                // get the right hand side of this operator
                var rightArg = ParseBinOperator(opExpr, opLevel, leftToRight);
                // build and return binary operator
                return(leftToRight ?
                       OperatorNode.BuildBinaryOperator(opLevel + 1, opText, rightArg, leftArg) : // if left-to-right, reversed arguments
                       OperatorNode.BuildBinaryOperator(opLevel + 1, opText, leftArg, rightArg)); // right-to-left, normal order
            }
            else                                                                                  // last arg - just return it
            {
                return(leftArg);
            }
        }
        /// <summary>
        /// Parse one line expression with ++ -- (postfix), function call, array subscript, slice subscript operators.
        /// Enumerator must be given with reversed ordering of arguments. This corresponds to Operator2Expression from Grammar.
        /// </summary>
        public static ExpressionNode ParseOperator2 <TSymbol>(IEnumerator <IParseTree <TSymbol> > opExpr) where TSymbol : ISymbol <TSymbol>
        {
            // O2 -> O1 (     "++" | "--"
            //           |    "(" (E ",")* E? ")"
            //           |    "[" E "]"
            //           |    "[" E? ".." E? "]"
            //          )*
            if (opExpr.Current.Symbol.IsTerminal)
            {
                string curText = ASTBuilder.EatTerminal(opExpr);
                switch (curText)
                {
                case "++":
                case "--":
                    return(OperatorNode.BuildUnaryOperator(2, curText, ParseOperator2(opExpr)));

                case ")":
                    var args = new LinkedList <ExpressionNode>();
                    while (!ASTBuilder.EatSymbol("(", opExpr))
                    {
                        ASTBuilder.EatSymbol(",", opExpr); // eat ',' before arg - f(x,y,z,) is also possible
                        args.AddFirst(GetExpressionNode(opExpr.Current));
                        opExpr.MoveNext();                 // move to next param with ','
                    }
                    var res = new FunctionCallNode();
                    res.Arguments = new List <ExpressionNode>(args);
                    // TODO: can something return a 'pointer' to function which we can call to execute?
                    res.Name = opExpr.Current.Fragment.GetOriginText();
                    return(res);

                case "]":
                    var  toExpr   = ASTBuilder.EatNonTerminal(opExpr);  // slice to or index
                    bool isSlice  = ASTBuilder.EatSymbol("..", opExpr);
                    var  fromExpr = ASTBuilder.EatNonTerminal(opExpr);
                    Debug.Assert(ASTBuilder.EatSymbol("[", opExpr));
                    if (isSlice)     // slice subscript
                    {
                        return(SliceNode.CreateSliceNode(ParseOperator2(opExpr),
                                                         GetExpressionOrNull(fromExpr), GetExpressionOrNull(toExpr)));
                    }
                    else     // array subscript
                    {
                        return(ElementNode.Create(ParseOperator2(opExpr), GetExpressionNode(toExpr)));
                    }

                default:
                    Debug.Assert(false);
                    break;
                }
            }
            else // non-terminal -> Operator1Expression
            {
                var op1 = opExpr.Current;
                Debug.Assert(!opExpr.MoveNext());      // it must be final symbol in this enumeration
                var node = ASTBuilder.FirstChild(op1); // Operator1Expression -> Operator0Expression
                // Operator0Expression -> AtomicExpression | "(" Expression ")";
                var childs = ASTBuilder.ChildrenEnumerator(node);
                Debug.Assert(childs.MoveNext());
                if (ASTBuilder.EatSymbol("(", childs))
                {
                    return(GetExpressionNode(childs.Current)); // Expression
                }
                else // proceed with AtomicExpression
                {
                    return(ResolveAtomicExpression(childs.Current));
                }
            }
            return(null);
        }