static IExpression ParseUntil(MathExpressionReader r, Stack<Operator> opStack, Stack<IExpression> output, Token readUntilToken, int startOpStackSize) { do { switch (r.CurrentTokenType) { case Token.LeftParens: { opStack.Push(Ops[OperationType.LeftParens]); r.ReadToken(); var arg = ParseUntil(r, opStack, output, Token.Coma | Token.RightParens, opStack.Count); if (r.CurrentTokenType == Token.Coma) throw new InvalidDataException("Tuples not supported"); if (r.CurrentTokenType != Token.RightParens) throw new InvalidDataException("Mismatched parens, missing a closing parens"); output.Push(arg); while (opStack.TryPeek(out var stackOp) && stackOp.Type != OperationType.LeftParens) { opStack.Pop(); PopOpOperandsAndPushNode(stackOp); } if (opStack.TryPeek(out var leftParens) && leftParens.Type == OperationType.LeftParens) opStack.Pop(); else throw new InvalidDataException("Mismatched parens"); r.ReadToken(); break; }
/// <summary> /// Parses a mathematical expression. /// </summary> /// <param name="expressionStr">The expression in string to be parsed.</param> /// <param name="error">The error message if an exception occured.</param> /// <returns>An IExpression that contains the parsed expression.</returns> public static IExpression Parse(string expressionStr, out string error) { var output = new Stack<IExpression>(); var opStack = new Stack<Operator>(); var r = new MathExpressionReader(expressionStr); try { r.ReadToken(); error = null; return ParseUntil(r, opStack, output, Token.None, 0); } catch (Exception e) { error = e.Message; return null; } }