예제 #1
0
        /// <summary>
        /// 要素登録
        /// </summary>
        /// <param name="pItem">要素</param>
        /// <remarks>
        /// CalculatorItemBaseクラスおよび派生クラスを登録します。
        /// 登録する順番は数式に準じます。
        /// </remarks>
        public void Entry(CalculatorItemBase pItem)
        {
            if (pItem is CalculatorValueBase)
            {
                this.mStackValue.Push((CalculatorValue)pItem);
                return;
            }

            CalculatorOperatorBase opeThis = (CalculatorOperatorBase)pItem;

            // (
            if (opeThis.OperatorType == CalculatorOperatorBase.EnumOperatorType.Open)
            {
                this.mStackOperator.Push(opeThis);
                return;
            }

            // )
            if (opeThis.OperatorType == CalculatorOperatorBase.EnumOperatorType.Close)
            {
                while (true)
                {
                    CalculatorOperatorBase ope = this.mStackOperator.Pop();
                    ope.Calculation(this.mStackValue);

                    if (ope.OperatorType == CalculatorOperatorBase.EnumOperatorType.Open)
                    {
                        break;
                    }
                }
                return;
            }

            if (mStackOperator.Count == 0)
            {
                this.mStackOperator.Push(opeThis);
                return;
            }

            CalculatorOperatorBase opeBefore = mStackOperator.Peek();

            int priority = opeBefore.ComparePriority(opeThis);

            if (priority < 0)
            {
                this.mStackOperator.Push(opeThis);
                return;
            }

            opeBefore.Calculation(this.mStackValue);
            mStackOperator.Pop();

            this.mStackOperator.Push(opeThis);
        }
        /// <summary>
        /// Performs the Shunting-Yard Algorithm
        /// </summary>
        public void Shunt()
        {
            // O(n)

            if (!ShuntValid)
            {
                throw new Exception("Shunt() was called without proper initialisation. Check ShuntValid first!");
            }

            var working = new List <Symbol>();

            foreach (var symbol in Input)
            {
                if (symbol.GetType() == typeof(Operand))
                {
                    working.Add(symbol);                                      // Add any numbers straight to output
                }
                else if (symbol.ToString() != "(" && symbol.ToString() != ")")
                { // Operators
                    var op = (Operator)symbol;

                    // If function, Push() to stack and continue;
                    if (op.Op == Operators.Function)
                    {
                        OperatorStack.Push(op);
                        continue;
                    }

                    while ((OperatorStack.Count != 0 && // Stack not empty!
                            (OperatorStack.Peek().Precedence >
                             op.Precedence || // Top operator has higher precedence than current one
                             (OperatorStack.Peek().Precedence == op.Precedence && !OperatorStack.Peek().IsRightAssociative))
                            ) && // Top op has equal precendence and is left associative
                           OperatorStack.Peek().Op != Operators.OpenBracket)    // Top op is not opening bracket
                    {
                        working.Add(OperatorStack.Pop());
                    }

                    OperatorStack.Push(op); // Add operator to stack
                }
                else
                {
                    switch (symbol.ToString())
                    {
                    case "(": // Opening Bracket
                        OperatorStack.Push((Operator)symbol);
                        break;

                    case ")": // Closing Bracket
                    {
                        while (OperatorStack.Peek().Op != Operators.OpenBracket)
                        {
                            if (OperatorStack.Count == 0)
                            {
                                throw new Exception("Ran out of stack while looking for left bracket: input had mismatched brackets.");
                            }
                            working.Add(OperatorStack.Pop());
                        }

                        if (OperatorStack.Peek().Op == Operators.OpenBracket)
                        {
                            OperatorStack.Pop();                                                   // Discard extra brackets
                        }
                        break;
                    }
                    }
                }
            }

            working.AddRange(OperatorStack); // Final step: pop out entire stack to output
            OperatorStack.Clear();           // Apparently AddRange() will Peek() instead of Pop() if the stack only has one element, failing to clear it

            Output = working.ToArray();
        }