/// <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;
        }