/// <summary> /// Calculates value of the expression of many variables. /// </summary> /// <param name="variables">Variables</param> /// <returns>Value of the expression</returns> public double Calculate(params Var[] variables) { Stack stack = new Stack(); foreach (Token t in reversePolishNotation) { if (t.Type == TokenType.Number) { stack.Push(t); } else if (t.Type == TokenType.Operator) { string operand1Str = stack.Pop().Lexeme.Replace(',', '.'); string operand2Str = stack.Pop().Lexeme.Replace(',', '.'); double operand1 = double.Parse(operand1Str, CultureInfo.InvariantCulture); double operand2 = double.Parse(operand2Str, CultureInfo.InvariantCulture); double smallResult = operators[t.Lexeme](operand1, operand2); stack.Push(new Token(smallResult.ToString(CultureInfo.InvariantCulture), TokenType.Number)); } else if (t.Type == TokenType.Function) { string operandStr = stack.Pop().Lexeme.Replace(',', '.'); double operand = double.Parse(operandStr, CultureInfo.InvariantCulture); double smallResult = functions[t.Lexeme](operand); stack.Push(new Token(smallResult.ToString(CultureInfo.InvariantCulture), TokenType.Number)); } else if (t.Type == TokenType.Constant) { double constant = constants[t.Lexeme]; stack.Push(new Token(constant.ToString(CultureInfo.InvariantCulture), TokenType.Number)); } else if (t.Type == TokenType.Variable) { Token smallToken = new Token(); foreach (Var variable in variables) { if (t.Lexeme == variable.Name) { smallToken = new Token(variable.Value.ToString(CultureInfo.InvariantCulture), TokenType.Number); break; } } stack.Push(smallToken); } else { throw new ArgumentException("Bad expression string."); } } double result = double.Parse(stack.Pop().Lexeme, CultureInfo.InvariantCulture); return result; }
/// <summary> /// Converts sequence of tokens from infix notation to postfix (reverse polish notation). /// See Shunting-yard algorithm for details. /// </summary> /// <param name="tokens">Sequence of tokens in infix notation</param> /// <returns>Sequence of tokens in reverse polish notation</returns> private List<Token> ConvertToReversePolishNotation(List<Token> tokens) { List<Token> reversePolishNotation = new List<Token>(); Stack stack = new Stack(); foreach (Token t in tokens) { if (t.Type == TokenType.Number || t.Type == TokenType.Variable || t.Type == TokenType.Constant) { reversePolishNotation.Add(t); } else if (t.Type == TokenType.Function) { stack.Push(t); } else if (t.Lexeme == "(") { stack.Push(t); } else if (t.Type == TokenType.Operator && t.Lexeme != ")") { if (!stack.Empty()) { while (stack.Top().Type == TokenType.Operator && t.Priority <= stack.Top().Priority) { reversePolishNotation.Add(stack.Pop()); if (stack.Empty()) { break; } } stack.Push(t); } else { stack.Push(t); } } else if (t.Type == TokenType.Operator && t.Lexeme == ")") { if (!stack.Empty()) { while (stack.Top().Lexeme != "(") { reversePolishNotation.Add(stack.Pop()); if (stack.Empty()) { break; } } stack.Pop(); if (!stack.Empty()) { if (stack.Top().Type == TokenType.Function) { reversePolishNotation.Add(stack.Pop()); } } } } } while (!stack.Empty()) { reversePolishNotation.Add(stack.Pop()); } return reversePolishNotation; }