Exemplo n.º 1
0
        /// <summary>
        /// Transform an infix expression string into
        /// a postfix expression string
        /// </summary>
        public Stack<string> InfixToPostfix(string expression)
        {
            var operands = new Stack<Token>();
            var postfix = new Stack<Token>();

            foreach (Token token in expression.Tokens()) {
                if (token.IsEmpty) continue;

                switch (token.Class) {
                    case TokenClass.Name:
                    case TokenClass.Operand:
                        #region Test for uniary operator
                        if (operands.HasItems()
                            && operands.Peek().Class == TokenClass.UniaryPrefix) {
                            switch (operands.Peek().Value) {
                                case "-":
                                    // turn a uniary minus and operand into a negative operand
                                    operands.Pop();
                                    postfix.Push(token);
                                    postfix.Push(new Token("-1"));
                                    postfix.Push(new Token("*"));
                                    break;
                                case "+":
                                    // no change to operand, remove uniary
                                    postfix.Push(token);
                                    operands.Pop();
                                    break;
                                default:
                                    throw new Exception("Unexpected operator");
                            }

                        #endregion
                        } else {
                            postfix.Push(token);
                        }
                        break;
                    case TokenClass.UniaryPostfix:
                        operands.Push(token);
                        break;
                    case TokenClass.UniaryPrefix:
                    case TokenClass.Function:
                    case TokenClass.OpenBracket:
                        #region Test for uniary operator
                        if (operands.HasItems()
                            && operands.Peek().Class == TokenClass.UniaryPrefix) {
                            switch (operands.Peek().Value) {
                                case "-":
                                    // change value, which will get picked up on bracket close
                                    token.Value = "-";
                                    operands.Pop(); // remove uniary
                                    operands.Push(token); // push bracket
                                    break;
                                case "+":
                                    operands.Pop(); // remove uniary
                                    operands.Push(token); // push bracket
                                    break;
                                default:
                                    throw new Exception("Unexpected operator");
                            }
                        #endregion
                        } else {
                            operands.Push(token);
                        }
                        break;

                    case TokenClass.ArgumentSeperator:
                        while (operands.HasItems()
                            && operands.Peek().Class != TokenClass.OpenBracket) {
                            if (operands.Count < 1) throw new Exception("Argument seperator outside of argument list");
                            postfix.Push(operands.Pop());
                        }
                        break;

                    case TokenClass.BinaryOperator:
                        while (operands.HasItems()
                            && token.ShouldDisplace(operands.Peek())) { // compare precedence
                            postfix.Push(operands.Pop());
                        }
                        operands.Push(token);
                        break;

                    case TokenClass.CloseBracket:
                        while (operands.HasItems()
                            && operands.Peek().Class != TokenClass.OpenBracket) { // add inner bracket contents
                            postfix.Push(operands.Pop());
                        }
                        #region Check for previously caught uniary minus bracket "-(...)"
                        if (operands.HasItems()) {
                            Token ob = operands.Pop(); // check open bracket
                            if (ob.Value == "-") { // invert value
                                postfix.Push(new Token("-1"));
                                postfix.Push(new Token("*"));
                            }
                        }
                        #endregion
                        if (operands.HasItems()
                            && operands.Peek().Class == TokenClass.Function) {// this is actually a function
                            postfix.Push(operands.Pop());
                        }
                        break;

                    default:
                        throw new Exception("Unexpected token: " + token.Value);
                } // end of switch
            } // end of token stream

            // deal with any remaining operators
            while (operands.HasItems()) { // compare precedence
                postfix.Push(operands.Pop());
            }

            var output = new Stack<string>(postfix.Count);
            foreach (Token t in postfix) output.Push(t.Value.Trim());
            return output;
        }