// Woops. This is left-associative. I wanted a right-associative tree. public static Expression fromString(String s, PrecedenceRule rule) { List <Token> tokens = tokenize(s); // dumpTokens(tokens); // tokens.Reverse(); return(fromTokens(tokens, rule)); }
public static Expression fromTokens(List <Token> tokens, PrecedenceRule rule) { Stack <TokenOrExpression> stack = new Stack <TokenOrExpression>(); while (true) { if (tokens.Count == 0 && stack.Count == 1 && stack.Peek()?.Expression != null) { return(stack.Pop().Expression); } if (stack.Count == 0) { stack.Push(new TokenOrExpression(tokens[0])); tokens.RemoveAt(0); } else if (stack.Peek()?.Token is LiteralToken) { ulong val = (stack.Pop().Token as LiteralToken).Value; stack.Push(new TokenOrExpression(new Literal(val))); } else if (stack.Peek()?.Token is RparenToken) { stack.Pop(); // Rparen Expression g = new Group(stack.Pop().Expression); stack.Pop(); // Lparen stack.Push(new TokenOrExpression(g)); } else if (stack.Peek()?.Expression != null) { bool reduce = true; if (rule == PrecedenceRule.PlusFirst) { int open = 0; int seen = 0; foreach (var t in tokens) { if (t is LparenToken) { open++; continue; } else if (t is RparenToken) { if (--open > 0) { continue; } else if (open < 0) { break; } } if (open == 0 && ++seen > 1) { break; } if (t is BinopToken) { BinopToken tok = t as BinopToken; if (tok.Kind == BinopKind.Plus) { reduce = false; break; } } } } Expression e1 = stack.Pop().Expression; if (reduce && stack.TryPeek(out TokenOrExpression top) && top.Token is BinopToken) { BinopToken binop = stack.Pop().Token as BinopToken; Expression e2 = stack.Pop().Expression; stack.Push(new TokenOrExpression(new Binop(e1, binop.Kind, e2))); } else // Probably Lparen { stack.Push(new TokenOrExpression(e1)); stack.Push(new TokenOrExpression(tokens[0])); tokens.RemoveAt(0); } }