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