public MathExpression Parse(TokenStream tokens)
{
#region Sanity Check
if (tokens == null)
{
throw new ArgumentNullException("tokens");
}
#endregion
// Not in postfix?
if (tokens.Notation != TokenNotation.Postfix)
{
throw new MathExpressionException("Invalid expression.", "Tokens are not in postfix notation.");
}
// No tokens in stream?
if (tokens.Count == 0)
{
// Treat this as zero.
return new NumericExpression(0D);
}
Stack<MathExpression> stack = new Stack<MathExpression>();
foreach (Token token in tokens)
{
if (token.Type == TokenType.Numeric)
{
// Create numeric expression.
stack.Push(new NumericExpression((double)token.Value));
}
else if (token.Type == TokenType.Constant)
{
// Create constant expression.
var constant = (Tuple<string, double>)token.Value;
stack.Push(new ConstantExpression(constant.Item1, constant.Item2));
}
else if (token.Type == TokenType.Variable)
{
// Create variable expression.
stack.Push(new VariableExpression((string)token.Value));
}
else if (token.Type == TokenType.Function)
{
// Get the function.
string functionName = (string)token.Value;
MathExpressionFunction function = MathExpressionFunctionFactory.Default.GetFunction(functionName);
// Make sure we got as many arguments on the stack as we have expected arguments.
if (stack.Count != function.ParameterCount)
{
string message = string.Format("Function '{0}' expect {1} argument(s).", function.Name, function.ParameterCount);
throw new MathExpressionException(message);
}
// Create the expression.
var args = stack.Pop(function.ParameterCount).Reverse(); // Arguments are reversed on the stack.
stack.Push(new FunctionExpression(function.Name, args.ToArray()));
}
else
{
// Make sure that the token is an operator.
if (!token.IsOperator())
{
throw new MathExpressionException("Invalid expression.", "Expected arithmetic operator in token stream.");
}
// Get the arithmetic operator for the token.
var @operator = token.GetArithmeticOperator();
if (@operator == ArithmeticOperator.Negation)
{
// Create negation expression.
MathExpression expression = stack.Pop();
stack.Push(new NegationExpression(expression));
}
else
{
// Create arithmetic expression.
MathExpression right = stack.Pop();
MathExpression left = stack.Pop();
ArithmeticExpression expression = new ArithmeticExpression(@operator, left, right);
stack.Push(expression);
}
}
}
// There should be exactly one expression on the stack.
if(stack.Count != 1)
{
throw new MathExpressionException("Invalid expression.", "There should be exactly one expression node on the stack.");
}
// Pop the expression from the stack.
return stack.Pop();
}