/// <summary> /// Initializes a new instance of the <see cref="ExpressionTree"/> class. /// </summary> /// <param name="expression">The arithmetic expression to be generated.</param> public ExpressionTree(string expression) { bool isSingleNodeTree = true; foreach (char op in this.Operators) { if (expression.Contains(op)) { isSingleNodeTree = false; break; } } if (isSingleNodeTree) { try { this.singleNodeDouble = Convert.ToDouble(expression); } catch (Exception) { this.singleNodeString = expression; } return; } // Generate the postfix notation for the expression. string[] postfixArray = this.ConvertToPostfix(expression); // Declare local variables. Node left, right; OperatorNode center; Stack <Node> nodeStack = new Stack <Node>(); ExpressionTreeFactory etf = new ExpressionTreeFactory(); // Iterate through each string in the postfix expression. for (int i = 0; i < postfixArray.Length; i++) { string s = postfixArray[i]; // Check for an empty string. if (s == string.Empty) { continue; } // Operator found! if (s.Length == 1 && this.Operators.Contains(s[0])) { // Create a new node with the top two nodes of the stack // as children and push it onto the top of the stack. center = (OperatorNode)etf.CreateNode(s); right = nodeStack.Pop(); left = nodeStack.Pop(); center.Left = left; center.Right = right; nodeStack.Push(center); } else { nodeStack.Push(etf.CreateNode(s)); // Push a non-operator node onto the stack. } } // Set the new head of the expression tree. this.head = (OperatorNode)nodeStack.Peek(); nodeStack.Pop(); }
/// <summary> /// Edsger Dijkstra's Shunting Yard algorithm to convert an infix expression into postfix expression. /// </summary> /// <param name="infixExpression"> Infix expression. </param> /// <returns> Postfix expression. </returns> private Queue <Node> ShuntingYardAlgorithm(string infixExpression) { Queue <Node> postfixExpression = new Queue <Node>(); Stack <OperatorNode> operatorStack = new Stack <OperatorNode>(); for (int index = 0; index < infixExpression.Length;) { // Need to create substring until the first operator in the expression is reached. string substring = string.Empty; int substringIndex; for (substringIndex = index; substringIndex < infixExpression.Length && !ExpressionTreeFactory.MatchesCharacter(infixExpression[substringIndex]); substringIndex++) { substring += infixExpression[substringIndex]; } // If the substring is a number then turn that substring into one. if (double.TryParse(substring, out double numSubstring)) { postfixExpression.Enqueue(new ConstantNode() { Value = numSubstring }); index = substringIndex; } else { if (ExpressionTreeFactory.MatchesOperator(infixExpression[index])) { OperatorNode op = ExpressionTreeFactory.CreateOperatorNode(infixExpression[index]); try { // If there are operators on the operatorStack with higher precedence than op then they need to be removed from the stack and added to the postfixExpression first. while (operatorStack.Peek().Precedence >= op.Precedence && operatorStack.Peek().Operator != '(') { postfixExpression.Enqueue(operatorStack.Pop()); } } catch { // Possible for there to be an empty operatorStack. In that case, nothing happens. } operatorStack.Push(op); } else if (infixExpression[index] == '(') { operatorStack.Push(new OperatorNode('(') { Precedence = 4 }); } else if (infixExpression[index] == ')') { try { while (operatorStack.Peek().Operator != '(') { postfixExpression.Enqueue(operatorStack.Pop()); } } catch { throw new ArgumentException("Missing a left parenthesis"); } operatorStack.Pop(); } else { // If the substring cannot be parsed as a double (constant) or parentheses then it's a variable. postfixExpression.Enqueue(new VariableNode() { Name = substring }); if (!this.Variables.ContainsKey(substring)) { this.SetVariable(substring, 0); } index = substringIndex - 1; } index++; } } // End of the expression, popping all operators onto the queue while (operatorStack.Count != 0) { if (operatorStack.Peek().Operator != '(') { postfixExpression.Enqueue(operatorStack.Pop()); } else { throw new ArgumentException("Missing a right parenthesis"); } } return(postfixExpression); }