/// <summary> /// Evaluate expression with Dijkstra's Shunting Yard Algorithm /// </summary> /// <returns>result of calculations</returns> public double?Calculate() { if (_input == null) { throw new ArgumentException(); } Stack <Op> operatorStack = new Stack <Op>(); Queue <Op> outputQueue = new Queue <Op>(); // Let's split the input string into a token list List <String> tokenList = Regex.Split(_input, TokenSplitRegex).Select(t => t.Trim()).Where(t => !String.IsNullOrEmpty(t)).ToList(); for (int tokenNum = 0; tokenNum < tokenList.Count(); ++tokenNum) { double? tmpValue; String token = tokenList[tokenNum]; TokenType tokenType = GetTokenType(token, out tmpValue); // Handle this token and insert into the correct queue or stack switch (tokenType) { case TokenType.Value: if (tmpValue.HasValue) { outputQueue.Enqueue(new Operand(tmpValue.Value)); } else { throw new ArgumentException("Unknown operand " + token); } break; case TokenType.Operator: Operator newOperator = GetOperator(token, (tokenNum == 0 || tokenList[tokenNum - 1] == "(")); if (operatorStack.Count > 0) { Op topOperator = operatorStack.Peek(); if (topOperator is Operator) { if (newOperator.Precedence <= ((Operator)topOperator).Precedence) { outputQueue.Enqueue(operatorStack.Pop()); } } } operatorStack.Push(newOperator); break; case TokenType.LeftParenthesis: operatorStack.Push(new LeftParenthesis()); break; case TokenType.RightParenthesis: // Handle all operators in the stack (i.e. move them to the outputQueue) // until we find the LeftParenthesis while (!(operatorStack.Peek() is LeftParenthesis)) { outputQueue.Enqueue(operatorStack.Pop()); } operatorStack.Pop(); break; case TokenType.Function: if ((tokenList.Count >= tokenNum + 1) && (tokenList[tokenNum + 1] == "(")) { Function.FunctionTypes type = Function.GetFunctionType(token); if (type == Function.FunctionTypes.UNKNOWN) { throw new ArgumentException("Unknown function " + token); } operatorStack.Push(new Function(type)); } break; } // If we don't find any token between a value and parenthesis, automatically // add a multiply sign if (tokenType == TokenType.Value || tokenType == TokenType.RightParenthesis) { if (tokenNum < tokenList.Count() - 1) { String nextToken = tokenList[tokenNum + 1]; TokenType nextTokenType = GetTokenType(nextToken, out tmpValue); if (nextTokenType != TokenType.Operator && nextTokenType != TokenType.RightParenthesis) { tokenList.Insert(tokenNum + 1, "*"); } } } } // Move all operators into the outputqueue while (operatorStack.Count > 0) { Op operand = operatorStack.Pop(); if (operand is LeftParenthesis || operand is RightParenthesis) { throw new ArgumentException("Mismatched parentheses"); } outputQueue.Enqueue(operand); } // Now we have the expression in reverse polish notation and it's easy to calculate // Step through the outputQueue and calculate the result Stack <Operand> outputStack = new Stack <Operand>(); while (outputQueue.Count > 0) { Op currentOp = outputQueue.Dequeue(); if (currentOp is Operand) { outputStack.Push((Operand)currentOp); } else if (currentOp is Operator) { Operator currentOperator = (Operator)currentOp; currentOperator.Execute(outputStack, this.Mode); } } // If we haven't got only one answer, the formula is invalid, return that. if (outputStack.Count != 1) { throw new ArgumentException("Invalid formula"); } // Pop and return the result return(outputStack.Pop().Value); }