/// <summary> /// Parses an infix expression into a an RPN token queue. /// </summary> /// <param name="expression">The expression to parse.</param> /// <returns>An RPN token queue.</returns> public ExpressionQueue Parse(string expression) { ExpressionQueue output = new ExpressionQueue(expression); Stack <Token> stack = new Stack <Token>(); if (!string.IsNullOrEmpty(expression)) { int i = 0; ReadResult result; while (i < expression.Length) { result = this.ReadOperand(expression, i); if (result.Success) { output.Enqueue(result.Token); i = result.Position; } else { result = this.ReadOperator(expression, i); if (result.Success) { RaspyOperator op1 = (RaspyOperator)result.Token; while (stack.Count > 0 && stack.Peek().IsOperator) { RaspyOperator op2 = (RaspyOperator)stack.Peek(); if ((op1.Associativity == Associativity.Left && op1.Precedence <= op2.Precedence) || (op1.Associativity == Associativity.Right && op1.Precedence < op2.Precedence)) { output.Enqueue(stack.Pop()); } else { break; } } stack.Push(result.Token); i = result.Position; } else if (expression[i] == '(') { stack.Push(new Parenthesis(ParenthesisType.Left)); i++; } else if (expression[i] == ')') { bool foundLeft = false; while (stack.Count > 0) { Token token = stack.Peek(); if (token.IsOperator) { output.Enqueue(stack.Pop()); } else if (token.IsParenthesis) { if (((Parenthesis)token).ParenthesisType == ParenthesisType.Left) { stack.Pop(); foundLeft = true; break; } } } i++; if (!foundLeft) { throw new RaspyParseException("The expression contains mismatched parentheses.", expression); } } else if (!char.IsWhiteSpace(expression[i])) { throw new RaspyParseException(string.Format(CultureInfo.InvariantCulture, "The expression contains an invalid character, '{0}'.", expression[i]), expression); } else { i++; } } } while (stack.Count > 0) { Token token = stack.Peek(); if (!token.IsParenthesis) { output.Enqueue(stack.Pop()); } else { throw new RaspyParseException("The expression contains mismatched parentheses.", expression); } } } return(output); }
/// <summary> /// Evaluates a parsed arithmetic expression. /// </summary> /// <param name="expression">The expression to evaluate.</param> /// <returns>The result of the evaluation.</returns> public object Evaluate(ExpressionQueue expression) { if (expression == null) { throw new ArgumentNullException("expression", "expression cannot be null."); } string infixExpression = expression.InfixExpression; string parsedExpression = expression.ToString(); Stack <Token> stack = new Stack <Token>(); try { while (expression.Count > 0) { Token token = expression.Dequeue(); if (token.IsOperator) { RaspyOperator op = (RaspyOperator)token; IOperationProvider provider = this.providerFactory.GetProvider(op.Symbol); if (provider != null) { List <Token> args = new List <Token>(); int i = op.ArgumentCount; while (i-- > 0) { args.Add(stack.Pop()); } args.Reverse(); stack.Push(provider.Operate(op, args.ToArray())); } else { throw new RaspyEvaluationException( string.Format(CultureInfo.InvariantCulture, "No provider could be found for operator '{0}'.", op.Symbol), infixExpression, parsedExpression); } } else { stack.Push(token); } } if (stack.Count != 1 || !stack.Peek().IsOperand) { throw new RaspyEvaluationException( string.Format(CultureInfo.InvariantCulture, "Invalid expression: '{0}'.", parsedExpression), infixExpression, parsedExpression); } return(((Operand)stack.Pop()).Value); } catch (RaspyException) { throw; } catch (Exception ex) { throw new RaspyEvaluationException( string.Format(CultureInfo.InvariantCulture, "An error occurred while evaluating the expression '{0}'.", parsedExpression), ex, infixExpression, parsedExpression); } }