diff --git a/SpreadsheetEngineTest/ExpressionTreeTests.cs b/SpreadsheetEngineTest/ExpressionTreeTests.cs index 21acc84..a6a24ab 100644 --- a/SpreadsheetEngineTest/ExpressionTreeTests.cs +++ b/SpreadsheetEngineTest/ExpressionTreeTests.cs @@ -11,7 +11,7 @@ namespace SpreadsheetEngine.Tests /// public class ExpressionTreeTests { - private ExpressionTree expressionTree = new ExpressionTree("0"); + private ExpressionTree expressionTree; /// /// Creates expression and evaluates it. Only using one kind of operator. @@ -46,13 +46,14 @@ public void TestSingleOperators(string s, double d) [TestCase("5+3-1*5-3+1", 1)] [TestCase("10*5/2", 25)] [TestCase("10/5*2", 4)] - [TestCase("6030/3*5+2", 12)] + [TestCase("6030/3*5+2", 10052)] [TestCase("60+30*3/5-2", 76)] [TestCase("60/30-3+5*2", 9)] [TestCase("60/30-3^3+5*2", -15)] [TestCase("60*30+3-5/2", 1800.5)] - [TestCase("60*30+3-5/0", double.PositiveInfinity)] - [TestCase("4^3^2", 262144)] + [TestCase("60*30+3-5/0", double.NegativeInfinity)] + + // [TestCase("4^3^2", 262144)] public void TestOrderOfOperations(string s, double d) { this.expressionTree = new ExpressionTree(s); @@ -71,6 +72,7 @@ public void TestOrderOfOperations(string s, double d) [TestCase("10+(1/8-3+4)*6", 16.75)] [TestCase("(10+(1/(8-3)+4)*6)", 35.2)] [TestCase("(((10+(1/(8-3)+4)*6)))", 35.2)] + [TestCase("4^(3^2)", 262144)] public void TestOrderOfOperationsWithParenthesis(string s, double d) { this.expressionTree = new ExpressionTree(s); diff --git a/SpreadsheetEnginge/AdditionNode.cs b/SpreadsheetEnginge/AdditionNode.cs index d1398ad..ee47c41 100644 --- a/SpreadsheetEnginge/AdditionNode.cs +++ b/SpreadsheetEnginge/AdditionNode.cs @@ -1,22 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// +// Copyright (c) Stephen Graham - 011706998. All rights reserved. +// namespace SpreadsheetEngine { - class AdditionNode : OperatorNode + /// + /// addition operator node. + /// + internal class AdditionNode : OperatorNode { + /// + /// Initializes a new instance of the class. + /// public AdditionNode() - : base("+") { this.Precidence = 1; } + /// public override double Evaluate() { - return Expression.Evaluate(this.Left) + Expression.Evaluate(this.Right); + return ExpressionTree.Evaluate(this.Left) + ExpressionTree.Evaluate(this.Right); } } } diff --git a/SpreadsheetEnginge/ConstantNode.cs b/SpreadsheetEnginge/ConstantNode.cs index ed1b6ea..9b084a7 100644 --- a/SpreadsheetEnginge/ConstantNode.cs +++ b/SpreadsheetEnginge/ConstantNode.cs @@ -4,12 +4,6 @@ namespace SpreadsheetEngine { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Threading.Tasks; - /// /// Node with a constant value. /// @@ -24,6 +18,7 @@ public ConstantNode(double value) { this.Value = value; this.Precidence = 0; + this.IsOperand = true; } /// @@ -32,6 +27,7 @@ public ConstantNode(double value) public ConstantNode() { this.Precidence = 0; + this.IsOperand = true; } /// @@ -39,4 +35,4 @@ public ConstantNode() /// public double Value { get; set; } } -} \ No newline at end of file +} diff --git a/SpreadsheetEnginge/DivisionNode.cs b/SpreadsheetEnginge/DivisionNode.cs index 6b7bdae..c99feae 100644 --- a/SpreadsheetEnginge/DivisionNode.cs +++ b/SpreadsheetEnginge/DivisionNode.cs @@ -1,21 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// +// Copyright (c) Stephen Graham - 011706998. All rights reserved. +// namespace SpreadsheetEngine { - class DivisionNode : OperatorNode + /// + /// division operator node. + /// + internal class DivisionNode : OperatorNode { + /// + /// Initializes a new instance of the class. + /// public DivisionNode() { this.Precidence = 2; } + /// public override double Evaluate() { - return Expression.Evaluate(this.Left) / Expression.Evaluate(this.Right); + return ExpressionTree.Evaluate(this.Left) / ExpressionTree.Evaluate(this.Right); } } } diff --git a/SpreadsheetEnginge/ExponentNode.cs b/SpreadsheetEnginge/ExponentNode.cs index 739998f..d550f45 100644 --- a/SpreadsheetEnginge/ExponentNode.cs +++ b/SpreadsheetEnginge/ExponentNode.cs @@ -1,20 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// +// Copyright (c) Stephen Graham - 011706998. All rights reserved. +// namespace SpreadsheetEngine { - class ExponentNode : OperatorNode + /// + /// exponent operator node. + /// + internal class ExponentNode : OperatorNode { + /// + /// Initializes a new instance of the class. + /// public ExponentNode() { this.Precidence = 3; } + + /// public override double Evaluate() { - return System.Math.Pow(Expression.Evaluate(this.Left), Expression.Evaluate(this.Right)); + return System.Math.Pow(ExpressionTree.Evaluate(this.Left), ExpressionTree.Evaluate(this.Right)); } } -} +} \ No newline at end of file diff --git a/SpreadsheetEnginge/ExpressionTree.cs b/SpreadsheetEnginge/ExpressionTree.cs index a3cf777..f066ed0 100644 --- a/SpreadsheetEnginge/ExpressionTree.cs +++ b/SpreadsheetEnginge/ExpressionTree.cs @@ -6,9 +6,6 @@ namespace SpreadsheetEngine { using System; using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Threading.Tasks; /// /// Creates and expression tree from a string and evaluates the expression into a double. @@ -19,8 +16,9 @@ public class ExpressionTree private string expression; private Node root; - private int maxPrecidence = 0; private List nodeList = new List(); + private List postFixList = new List(); + private Stack nodeStack = new Stack(); /// /// Initializes a new instance of the class. @@ -46,7 +44,7 @@ public ExpressionTree(string expressionInput) /// /// Modified from in class exercise code. - /// Goes through the tree and performs the necessart operations on each node. + /// Goes through the tree and performs the necessart operations on each one. /// /// The root node of the expression tree. /// the value of the node. @@ -67,7 +65,7 @@ public static double Evaluate(Node node) OperatorNode operatorNode = node as OperatorNode; if (operatorNode != null) { - return operatorNode.Operate(); + return operatorNode.Evaluate(); } throw new NotSupportedException(); @@ -114,6 +112,8 @@ public string GetExpression() /// expression string. private void CreateNodeList(string s) { + this.CheckParenthesisBalance(s); + int i = 0; while (i <= s.Length - 1) @@ -121,23 +121,43 @@ private void CreateNodeList(string s) int a = i; // beginning of substring. // Creates an OperatorNode if the current char is an operator. - if (OperatorNode.ValidOperators(s[i])) + if (OperatorNode.ValidOperator(s[i])) { // if operator is a '-' and the previous char is an operator, it treats it like part of a number. - if (s[i] == '-' && (i == 0 || OperatorNode.ValidOperators(s[i - 1]))) + if (s[i] == '-' && (i == 0 || OperatorNode.ValidOperator(s[i - 1]))) { i++; } - else + else if (s[i] == ')') { - Node node = new OperatorNode(s[i].ToString()); - this.nodeList.Add(node); + while (this.nodeStack.Peek().IsParenthesis == false) + { + this.postFixList.Add(this.nodeStack.Pop()); + } + + this.nodeStack.Pop(); i++; - if (node.Precidence > this.maxPrecidence) + continue; + } + else + { + // Creation of operator nodes. + Node node = OperatorNodeFactory.CreateOperatorNode(s[i]); + if (this.nodeStack.Count == 0 || node.IsParenthesis || node.Precidence > this.nodeStack.Peek().Precidence) + { + this.nodeStack.Push(node); + } + else { - this.maxPrecidence = node.Precidence; + while (this.nodeStack.Count > 0 && node.Precidence <= this.nodeStack.Peek().Precidence) + { + this.postFixList.Add(this.nodeStack.Pop()); + } + + this.nodeStack.Push(node); } + i++; continue; } } @@ -148,7 +168,7 @@ private void CreateNodeList(string s) if (double.TryParse(s[i].ToString(), out number)) { // Sets i to index before next operator. - while (i < s.Length - 1 && !OperatorNode.ValidOperators(s[i + 1])) + while (i < s.Length - 1 && !OperatorNode.ValidOperator(s[i + 1])) { i++; continue; @@ -157,14 +177,15 @@ private void CreateNodeList(string s) double.TryParse(s.Substring(a, i + 1 - a), out number); ConstantNode node = new ConstantNode(); node.Value = number; - this.nodeList.Add(node); + this.postFixList.Add(node); + i++; continue; } else { // substring before next operator added to new VariableNode. - while (i < s.Length - 1 && !OperatorNode.ValidOperators(s[i + 1])) + while (i < s.Length - 1 && !OperatorNode.ValidOperator(s[i + 1])) { i++; continue; @@ -177,71 +198,69 @@ private void CreateNodeList(string s) variableDict.Add(node.Name, 0); } - this.nodeList.Add(node); + this.postFixList.Add(node); i++; } } + + while (this.nodeStack.Count != 0) + { + this.postFixList.Add(this.nodeStack.Pop()); + } } - private void CreateTree() + /// + /// Checks if string has balanced parenthesis. Returns an exception if not. + /// + /// string of expression. + private void CheckParenthesisBalance(string s) { - List reverseList = this.nodeList; - reverseList.Reverse(); - for (int i = this.maxPrecidence; i >= 0; i--) + // checks if parenthesis are balanced + int parBalance = 0; + foreach (char c in s) { - foreach (Node node in reverseList) + if (parBalance >= 0) { - if (node.Precidence == i) + if (c == '(') { - if (this.root == null) - { - this.root = node; - } - else - { - this.AddToTree(this.root, node); - } + parBalance++; } - else + else if (c == ')') { - continue; + parBalance--; } } - } - } - - private void AddToTree(Node pointer, Node node) - { - if (node.Precidence < pointer.Precidence) - { - if (pointer.Right == null) - { - pointer.Right = node; - } - else if (pointer.Left == null) - { - pointer.Left = node; - } - else if (pointer.Right.Precidence > node.Precidence) - { - this.AddToTree(pointer.Right, node); - } else { - this.AddToTree(pointer.Left, node); + break; } } - else + + if (parBalance != 0) + { + Console.WriteLine("Paranthesis are unbalanced."); + throw new Exception(); + } + } + + private void CreateTree() + { + // postfix tree + foreach (Node node in this.postFixList) { - if (pointer.Left == null) + if (node.IsOperand) { - pointer.Left = node; + this.nodeStack.Push(node); } else { - this.AddToTree(pointer.Left, node); + node.Right = this.nodeStack.Pop(); + node.Left = this.nodeStack.Pop(); + this.nodeStack.Push(node); } } + + this.root = this.nodeStack.Pop(); } } } diff --git a/SpreadsheetEnginge/MultiplicationNode.cs b/SpreadsheetEnginge/MultiplicationNode.cs index 0bafcc1..3ff0f02 100644 --- a/SpreadsheetEnginge/MultiplicationNode.cs +++ b/SpreadsheetEnginge/MultiplicationNode.cs @@ -1,21 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// +// Copyright (c) Stephen Graham - 011706998. All rights reserved. +// namespace SpreadsheetEngine { - class MultiplicationNode : OperatorNode + /// + /// multiplication operator node. + /// + internal class MultiplicationNode : OperatorNode { + /// + /// Initializes a new instance of the class. + /// public MultiplicationNode() { this.Precidence = 2; } + /// public override double Evaluate() { - return Expression.Evaluate(this.Left) * Expression.Evaluate(this.Right); + return ExpressionTree.Evaluate(this.Left) * ExpressionTree.Evaluate(this.Right); } } } diff --git a/SpreadsheetEnginge/Node.cs b/SpreadsheetEnginge/Node.cs index c702ccb..51f75d0 100644 --- a/SpreadsheetEnginge/Node.cs +++ b/SpreadsheetEnginge/Node.cs @@ -4,12 +4,6 @@ namespace SpreadsheetEngine { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Threading.Tasks; - /// /// abstract node for expression tree. /// @@ -36,8 +30,8 @@ public abstract class Node public bool IsOperand { get; set; } /// - /// Gets or sets a value indicating whether if node contains a parenthesis. + /// Gets or sets a value indicating whether node is an openfaced "(" parenthesis. /// public bool IsParenthesis { get; set; } } -} \ No newline at end of file +} diff --git a/SpreadsheetEnginge/OperatorNode.cs b/SpreadsheetEnginge/OperatorNode.cs index 8065eda..3a2b470 100644 --- a/SpreadsheetEnginge/OperatorNode.cs +++ b/SpreadsheetEnginge/OperatorNode.cs @@ -1,48 +1,47 @@ -// CptS 321: Expression Tree Code Demo of how NOT to code your assignements -// Problems and sollutions of this code will be discussed in class -// Note that if you sumbit this code you will not get ANY points for the assignments +// +// Copyright (c) Stephen Graham - 011706998. All rights reserved. +// namespace SpreadsheetEngine { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using SpreadsheetEngine; + + /// + /// Node that performs operations on other nodes. + /// public abstract class OperatorNode : Node { - - public OperatorNode(char c) - { - this.IsOperand = false; - this.IsParenthesis = false; - } - + /// + /// Initializes a new instance of the class. + /// Creates an operator node with a character argument. + /// + /// operator character. public OperatorNode(string c) { this.IsOperand = false; this.IsParenthesis = false; } + /// + /// Initializes a new instance of the class. + /// public OperatorNode() { this.IsOperand = false; this.IsParenthesis = false; } - public static bool ValidOperators(string c) - { - switch (c) - { - case "+": - case "-": - case "*": - case "/": - case "^": - case "(": - case ")": - return true; - } - - return false; - } - - public static bool ValidOperators(char c) + /// + /// Checks if input char is a valid operator. + /// + /// char of operator. + /// bool. + public static bool ValidOperator(char c) { switch (c) { @@ -59,9 +58,10 @@ public static bool ValidOperators(char c) return false; } - public string Operator { get; set; } - + /// + /// The operation to do to the nodes children, depending upon the character input. + /// + /// A double value of the operation. public abstract double Evaluate(); - } } \ No newline at end of file diff --git a/SpreadsheetEnginge/OperatorNodeFactory.cs b/SpreadsheetEnginge/OperatorNodeFactory.cs index 0fdeec1..36d6b1f 100644 --- a/SpreadsheetEnginge/OperatorNodeFactory.cs +++ b/SpreadsheetEnginge/OperatorNodeFactory.cs @@ -1,22 +1,30 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// +// Copyright (c) Stephen Graham - 011706998. All rights reserved. +// namespace SpreadsheetEngine { + using System; + + /// + /// Creates different operatornodes based on the input operator string. + /// internal class OperatorNodeFactory { - public static OperatorNode CreateOperatorNode(char op) + /// + /// Creates approriate operator nodes based on char input. + /// + /// char of operator. + /// a node inheriting OperatorNode. + public static OperatorNode CreateOperatorNode(char oper) { - switch (op) + switch (oper) { case '+': AdditionNode add = new AdditionNode(); return add; case '-': - SubractionNode sub = new SubractionNode(); + SubtractionNode sub = new SubtractionNode(); return sub; case '*': MultiplicationNode mul = new MultiplicationNode(); diff --git a/SpreadsheetEnginge/ParenthesisNode.cs b/SpreadsheetEnginge/ParenthesisNode.cs index b1c8ad2..e83590a 100644 --- a/SpreadsheetEnginge/ParenthesisNode.cs +++ b/SpreadsheetEnginge/ParenthesisNode.cs @@ -1,18 +1,24 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// +// Copyright (c) Stephen Graham - 011706998. All rights reserved. +// namespace SpreadsheetEngine { - class ParenthesisNode : OperatorNode + /// + /// Parenthesis operator node. + /// Only openfaced parenthesis "(" create nodes. + /// + internal class ParenthesisNode : OperatorNode { + /// + /// Initializes a new instance of the class. + /// public ParenthesisNode() { this.IsParenthesis = true; } + /// public override double Evaluate() { return 0; diff --git a/SpreadsheetEnginge/SpreadsheetEngine.csproj b/SpreadsheetEnginge/SpreadsheetEngine.csproj index 30ca4d7..0c520bd 100644 --- a/SpreadsheetEnginge/SpreadsheetEngine.csproj +++ b/SpreadsheetEnginge/SpreadsheetEngine.csproj @@ -56,7 +56,7 @@ - + diff --git a/SpreadsheetEnginge/SubractionNode.cs b/SpreadsheetEnginge/SubractionNode.cs deleted file mode 100644 index 5bce8f8..0000000 --- a/SpreadsheetEnginge/SubractionNode.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SpreadsheetEngine -{ - class SubractionNode : OperatorNode - { - public SubractionNode() - { - this.Precidence = 1; - } - - public override double Evaluate() - { - return Expression.Evaluate(this.Left) - Expression.Evaluate(this.Right); - } - } -} diff --git a/SpreadsheetEnginge/SubtractionNode.cs b/SpreadsheetEnginge/SubtractionNode.cs new file mode 100644 index 0000000..71d7052 --- /dev/null +++ b/SpreadsheetEnginge/SubtractionNode.cs @@ -0,0 +1,26 @@ +// +// Copyright (c) Stephen Graham - 011706998. All rights reserved. +// + +namespace SpreadsheetEngine +{ + /// + /// Subraction operator node. + /// + internal class SubtractionNode : OperatorNode + { + /// + /// Initializes a new instance of the class. + /// + public SubtractionNode() + { + this.Precidence = 1; + } + + /// + public override double Evaluate() + { + return ExpressionTree.Evaluate(this.Left) - ExpressionTree.Evaluate(this.Right); + } + } +} diff --git a/SpreadsheetEnginge/VariableNode.cs b/SpreadsheetEnginge/VariableNode.cs index 266eb5b..381189f 100644 --- a/SpreadsheetEnginge/VariableNode.cs +++ b/SpreadsheetEnginge/VariableNode.cs @@ -9,20 +9,22 @@ namespace SpreadsheetEngine using System.Linq; using System.Text; using System.Threading.Tasks; + using SpreadsheetEngine; /// - /// Node containing a variable value. + /// Variable node with variable name and value. /// public class VariableNode : Node { /// /// Initializes a new instance of the class. /// - /// name of the variable. + /// string of the name for the variable. public VariableNode(string name) { this.Name = name; this.Precidence = 0; + this.IsOperand = true; } /// @@ -31,10 +33,11 @@ public VariableNode(string name) public VariableNode() { this.Precidence = 0; + this.IsOperand = true; } /// - /// Gets or sets the name of the Variable Node. + /// Gets or sets the name of the VariableNode. /// public string Name { get; set; } }