} // 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); }