diff --git a/ParsingTree/ParsingTree.sln b/ParsingTree/ParsingTree.sln
new file mode 100644
index 0000000..413afc6
--- /dev/null
+++ b/ParsingTree/ParsingTree.sln
@@ -0,0 +1,30 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.4.33403.182
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParsingTree", "ParsingTree\ParsingTree.csproj", "{E7D3B03D-F74E-4781-9DF2-0CB24880162A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestsForParsingTree", "TestsForParsingTree\TestsForParsingTree.csproj", "{92559259-B410-4FB3-B4A7-0A8AE15F68B1}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E7D3B03D-F74E-4781-9DF2-0CB24880162A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E7D3B03D-F74E-4781-9DF2-0CB24880162A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E7D3B03D-F74E-4781-9DF2-0CB24880162A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E7D3B03D-F74E-4781-9DF2-0CB24880162A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {92559259-B410-4FB3-B4A7-0A8AE15F68B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {92559259-B410-4FB3-B4A7-0A8AE15F68B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {92559259-B410-4FB3-B4A7-0A8AE15F68B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {92559259-B410-4FB3-B4A7-0A8AE15F68B1}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {4AF94C07-C87B-41B8-9B20-62E8562E599A}
+ EndGlobalSection
+EndGlobal
diff --git a/ParsingTree/ParsingTree/Divider.cs b/ParsingTree/ParsingTree/Divider.cs
new file mode 100644
index 0000000..7537d5e
--- /dev/null
+++ b/ParsingTree/ParsingTree/Divider.cs
@@ -0,0 +1,33 @@
+namespace ParsingTree;
+
+///
+/// A class for dividing numbers
+///
+public class Divider : Operator
+{
+ private double delta = 0.0000001;
+
+ ///
+ /// Inherits the ancestor's method
+ ///
+ /// Operator
+ public Divider(char symbol) : base(symbol) {}
+
+ ///
+ /// Counts the division of two numbers
+ ///
+ /// Throws an exception when dividing by zero
+ public override double Calcuate(double firstValue, double secondValue)
+ {
+ if (secondValue - Math.Abs(secondValue) < delta)
+ {
+ throw new ArgumentException();
+ }
+ return firstValue / secondValue;
+ }
+
+ ///
+ /// Prints the division sign in the console
+ ///
+ public override void Print() => Console.Write(" / ");
+}
diff --git a/ParsingTree/ParsingTree/InvalidExpressionException.cs b/ParsingTree/ParsingTree/InvalidExpressionException.cs
new file mode 100644
index 0000000..0a544e0
--- /dev/null
+++ b/ParsingTree/ParsingTree/InvalidExpressionException.cs
@@ -0,0 +1,6 @@
+namespace ParsingTree;
+
+///
+/// Throws an exception in case of an invalid expression
+///
+public class InvalidExpressionException : Exception {}
\ No newline at end of file
diff --git a/ParsingTree/ParsingTree/Minus.cs b/ParsingTree/ParsingTree/Minus.cs
new file mode 100644
index 0000000..82ab853
--- /dev/null
+++ b/ParsingTree/ParsingTree/Minus.cs
@@ -0,0 +1,25 @@
+namespace ParsingTree;
+
+///
+/// Subtracts from one number another
+///
+public class Minus : Operator
+{
+ ///
+ /// Inherits the method of the ancestor operator
+ ///
+ public Minus(char symbol) : base(symbol) {}
+
+ ///
+ /// Calculates the difference
+ ///
+ public override double Calcuate(double firstValue, double secondValue)
+ {
+ return secondValue - firstValue;
+ }
+
+ ///
+ /// Prints the minus sign
+ ///
+ public override void Print() => Console.Write(" - ");
+}
\ No newline at end of file
diff --git a/ParsingTree/ParsingTree/Multiplication.cs b/ParsingTree/ParsingTree/Multiplication.cs
new file mode 100644
index 0000000..5a32f08
--- /dev/null
+++ b/ParsingTree/ParsingTree/Multiplication.cs
@@ -0,0 +1,25 @@
+namespace ParsingTree;
+
+///
+/// Counts the multiplication of two numbers
+///
+public class Multiplication : Operator
+{
+ ///
+ /// Inherits the method of the ancestor operator
+ ///
+ public Multiplication(char symbol) : base(symbol) {}
+
+ ///
+ /// Multiplies two numbers by each other
+ ///
+ public override double Calcuate(double firstValue, double secondValue)
+ {
+ return firstValue * secondValue;
+ }
+
+ ///
+ /// Prints the multiply sign
+ ///
+ public override void Print() => Console.Write(" * ");
+}
diff --git a/ParsingTree/ParsingTree/Operand.cs b/ParsingTree/ParsingTree/Operand.cs
new file mode 100644
index 0000000..7571f53
--- /dev/null
+++ b/ParsingTree/ParsingTree/Operand.cs
@@ -0,0 +1,30 @@
+namespace ParsingTree;
+
+///
+/// A class based on numbers
+///
+public class Operand : PartOfExpression
+{
+ ///
+ /// Returns a stored number
+ ///
+ public double Calcuate(double firstValue, double secondValue)
+ {
+ return Number;
+ }
+
+ ///
+ /// Prints a number
+ ///
+ public void Print() => Console.Write(Number + ' ');
+
+ ///
+ /// saves a number
+ ///
+ public Operand(double number)
+ {
+ Number = number;
+ }
+
+ public double Number { get; set; }
+}
diff --git a/ParsingTree/ParsingTree/Operator.cs b/ParsingTree/ParsingTree/Operator.cs
new file mode 100644
index 0000000..ae33c5c
--- /dev/null
+++ b/ParsingTree/ParsingTree/Operator.cs
@@ -0,0 +1,27 @@
+namespace ParsingTree;
+
+///
+/// A class that includes multiply divide add and subtract
+///
+abstract public class Operator : PartOfExpression
+{
+ ///
+ /// Abstract type for an action account
+ ///
+ public abstract double Calcuate(double firstValue, double secondValue);
+
+ ///
+ /// Abstract type for printing characters
+ ///
+ public abstract void Print();
+
+ ///
+ /// Stores a symbol in itself
+ ///
+ public Operator(char symbol)
+ {
+ Symbol = symbol;
+ }
+
+ public char Symbol { get; set; }
+}
diff --git a/ParsingTree/ParsingTree/ParsingTree.csproj b/ParsingTree/ParsingTree/ParsingTree.csproj
new file mode 100644
index 0000000..f02677b
--- /dev/null
+++ b/ParsingTree/ParsingTree/ParsingTree.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/ParsingTree/ParsingTree/PartOfExpression.cs b/ParsingTree/ParsingTree/PartOfExpression.cs
new file mode 100644
index 0000000..37d97e4
--- /dev/null
+++ b/ParsingTree/ParsingTree/PartOfExpression.cs
@@ -0,0 +1,17 @@
+namespace ParsingTree;
+
+///
+/// Interface for implementing different parts of expressions
+///
+public interface PartOfExpression
+{
+ ///
+ /// Counts two numbers
+ ///
+ public double Calcuate(double firstValue, double secondValue);
+
+ ///
+ /// Prints a character or number
+ ///
+ public void Print();
+}
diff --git a/ParsingTree/ParsingTree/Plus.cs b/ParsingTree/ParsingTree/Plus.cs
new file mode 100644
index 0000000..3a07efb
--- /dev/null
+++ b/ParsingTree/ParsingTree/Plus.cs
@@ -0,0 +1,23 @@
+namespace ParsingTree;
+
+///
+/// A class that implements amount
+///
+public class Plus : Operator
+{
+ ///
+ /// Inherits the method of the ancestor of the operator
+ ///
+ ///
+ public Plus(char symbol) : base(symbol) {}
+
+ ///
+ /// Counts the Amount of two numbers
+ ///
+ public override double Calcuate(double firstValue, double secondValue) => secondValue + firstValue;
+
+ ///
+ /// Prints a plus sign with spaces
+ ///
+ public override void Print() => Console.Write(" + ");
+}
diff --git a/ParsingTree/ParsingTree/Program.cs b/ParsingTree/ParsingTree/Program.cs
new file mode 100644
index 0000000..e953f27
--- /dev/null
+++ b/ParsingTree/ParsingTree/Program.cs
@@ -0,0 +1,27 @@
+using ParsingTree;
+
+Tree tree = new Tree();
+Console.WriteLine("Input your string");
+string? stringExpression = Console.ReadLine();
+try
+{
+ if (stringExpression == null)
+ {
+ throw new ArgumentNullException(nameof(stringExpression));
+ }
+ tree.TreeExpression(stringExpression);
+ Console.WriteLine(tree.Calcuate());
+}
+catch (InvalidExpressionException)
+{
+ Console.WriteLine("Incorrect input");
+}
+catch (ArgumentException)
+{
+ Console.WriteLine("Try to divide by zero");
+}
+catch (NullReferenceException)
+{
+ Console.WriteLine("Try to Calcuate without tree");
+}
+tree.PrintExpression();
\ No newline at end of file
diff --git a/ParsingTree/ParsingTree/Tree.cs b/ParsingTree/ParsingTree/Tree.cs
new file mode 100644
index 0000000..3d4e0af
--- /dev/null
+++ b/ParsingTree/ParsingTree/Tree.cs
@@ -0,0 +1,253 @@
+namespace ParsingTree;
+
+///
+/// The container is a "tree" with a hierarchical structure
+///
+public class Tree
+{
+ private Node Root { get; set; }
+
+ private void AddToTree(Node root, ref bool isAdded, double value = 0, char symbol = '\0')
+ {
+ if (root != null)
+ {
+ if (root.IsEmpty && !isAdded)
+ {
+ if (symbol != '\0')
+ {
+ switch (symbol)
+ {
+ case '-':
+ root.Symbol = new Minus(symbol);
+ break;
+ case '+':
+ root.Symbol = new Plus(symbol);
+ break;
+ case '*':
+ root.Symbol = new Multiplication(symbol);
+ break;
+ case '/':
+ root.Symbol = new Divider(symbol);
+ break;
+ }
+ root.IsEmpty = false;
+ root.Left = new Node();
+ root.Right = new Node();
+ root.Left.Value = new Operand(0);
+ root.Right.Value = new Operand(0);
+ ++Root.Size;
+ }
+ else
+ {
+ root.Value.Number = value;
+ root.IsEmpty = false;
+ --Root.Size;
+
+ }
+ isAdded = true;
+ }
+ AddToTree(root.Left, ref isAdded, value, symbol);
+ AddToTree(root.Right, ref isAdded, value, symbol);
+ }
+ }
+
+ private void AddToTreeNumber(double value)
+ {
+ if (Root == null)
+ {
+ throw new InvalidExpressionException();
+ }
+ bool isAdded = false;
+ AddToTree(Root, ref isAdded, value);
+ if (!isAdded)
+ {
+ throw new InvalidExpressionException();
+ }
+ }
+
+ private void AddToTreeSymbol(char symbol)
+ {
+ if (Root == null)
+ {
+ Root = new Node();
+ switch (symbol)
+ {
+ case '-':
+ Root.Symbol = new Minus(symbol);
+ break;
+ case '+':
+ Root.Symbol = new Plus(symbol);
+ break;
+ case '*':
+ Root.Symbol = new Multiplication(symbol);
+ break;
+ case '/':
+ Root.Symbol = new Divider(symbol);
+ break;
+ }
+ Root.Symbol.Symbol = symbol;
+ Root.Value = new Operand(0);
+ Root.Left = new Node();
+ Root.Right = new Node();
+ Root.Right.Value = new Operand(0);
+ Root.Left.Value = new Operand(0);
+ Root.IsEmpty = false;
+ Root.Size += 2;
+ return;
+ }
+ bool isAdded = false;
+ AddToTree(Root, ref isAdded, 0, symbol);
+ if (!isAdded)
+ {
+ throw new InvalidExpressionException();
+ }
+ }
+
+ private bool isSymbolOperation(char symbol)
+ {
+ return symbol == '+'
+ || symbol == '-'
+ || symbol == '*'
+ || symbol == '/';
+ }
+
+ ///
+ /// Builds an expression tree by expression
+ ///
+ /// Throws an exception if the string is not correct
+ public void TreeExpression(string stringExpression)
+ {
+ for (int i = 0; i < stringExpression.Length; i++)
+ {
+ if(Char.IsNumber(stringExpression[i]) || (i < stringExpression.Length - 1 && stringExpression[i] == '-' && Char.IsNumber(stringExpression[i + 1])))
+ {
+ double number = 0;
+ bool isMinus = false;
+ if (stringExpression[i] == '-')
+ {
+ ++i;
+ isMinus = true;
+ }
+ while (i < stringExpression.Length && Char.IsNumber(stringExpression[i]))
+ {
+ number += stringExpression[i] - 48;
+ number *= 10;
+ ++i;
+ }
+ number /= 10;
+ if (isMinus)
+ {
+ number *= -1;
+ }
+ AddToTreeNumber(number);
+ }
+ else if (isSymbolOperation(stringExpression[i]))
+ {
+ AddToTreeSymbol(stringExpression[i]);
+ }
+ else if (stringExpression[i] != ' ' && stringExpression[i] != ')' && stringExpression[i] != '(')
+ {
+ throw new InvalidExpressionException();
+ }
+ }
+ if (Root.Size != 0 || Root == null)
+ {
+ throw new InvalidExpressionException();
+ }
+ }
+
+ private void Order(Node root)
+ {
+ if (root.Symbol != null)
+ {
+ Order(root.Left);
+ Order(root.Right);
+ if (root.Left.Symbol == null && root.Right.Symbol == null)
+ {
+ root.Value.Number = root.Symbol.Calcuate(root.Left.Value.Number, root.Right.Value.Number);
+ root.IsEmpty = true;
+ }
+ else
+ {
+ root.Value.Number = root.Symbol.Calcuate(root.Left.Value.Number, root.Right.Value.Number);
+ root.Left.IsEmpty = false;
+ root.Right.IsEmpty = false;
+ }
+ }
+ }
+
+ ///
+ /// Counts an expression in the tree
+ ///
+ ///
+ /// Throws an exception if the tree is empty
+ public double Calcuate()
+ {
+ if (Root == null)
+ {
+ throw new NullReferenceException();
+ }
+ Order(Root);
+ Root.IsEmpty = false;
+ return Root.Value.Number;
+ }
+
+ private void PostOrderPrint(Node root, ref int isPreviousNumber, ref int sizeBackStaples)
+ {
+ if (root != null)
+ {
+ if (root.Symbol == null)
+ {
+ ++isPreviousNumber;
+ root.Value.Print();
+ if (isPreviousNumber % 2 == 0 && isPreviousNumber != 0)
+ {
+ Console.Write(") ");
+ --sizeBackStaples;
+ isPreviousNumber = 0;
+ }
+ }
+ else
+ {
+ isPreviousNumber = 0;
+ Console.Write('(');
+ ++sizeBackStaples;
+ root.Symbol.Print();
+ }
+ PostOrderPrint(root.Left, ref isPreviousNumber, ref sizeBackStaples);
+ PostOrderPrint(root.Right, ref isPreviousNumber, ref sizeBackStaples);
+ }
+ }
+
+ ///
+ /// Outputs the expression stored in the tree to the screen
+ ///
+ public void PrintExpression()
+ {
+ int isPreviousNumber = 0;
+ int sizeBackStaples = 0;
+ PostOrderPrint(Root, ref isPreviousNumber, ref sizeBackStaples);
+ for (int i = 0; i < sizeBackStaples; ++i)
+ {
+ Console.Write(')');
+ }
+ }
+
+ private class Node
+ {
+ public Node()
+ {
+ IsEmpty = true;
+ }
+
+ public Operand Value { get; set; }
+
+ public Operator Symbol { get; set; }
+ public Node Left { get; set; }
+ public Node Right { get; set; }
+
+ public bool IsEmpty { get; set; }
+
+ public int Size { get; set; }
+ }
+}
diff --git a/ParsingTree/TestsForParsingTree/TestsForParsingTree.csproj b/ParsingTree/TestsForParsingTree/TestsForParsingTree.csproj
new file mode 100644
index 0000000..82281fa
--- /dev/null
+++ b/ParsingTree/TestsForParsingTree/TestsForParsingTree.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ParsingTree/TestsForParsingTree/TestsTree.cs b/ParsingTree/TestsForParsingTree/TestsTree.cs
new file mode 100644
index 0000000..2e73f7b
--- /dev/null
+++ b/ParsingTree/TestsForParsingTree/TestsTree.cs
@@ -0,0 +1,77 @@
+namespace TestsParsingTree;
+
+using ParsingTree;
+
+public class Tests
+{
+ Tree tree;
+ [SetUp]
+ public void Setup()
+ {
+ tree = new Tree();
+ }
+
+ [Test]
+ public void InTheUsualExampleTheTreeShouldCorrectlyCalculateTheValue()
+ {
+ tree.TreeExpression("+ 2 3");
+ Assert.True(tree.Calcuate() == 5);
+ }
+
+ [Test]
+ public void InTheNormalExampleTheTreeShouldCorrectlyCalculateTheValue()
+ {
+ tree.TreeExpression("(* (+ 2 3) (+ 5 7)");
+ Assert.True(tree.Calcuate() == 60);
+ }
+
+ [Test]
+ public void WhenAnEmptyStrinIsReceivedTheTreeShouldThrowAnException()
+ {
+ Assert.Throws(() => tree.TreeExpression(""));
+ }
+
+ [Test]
+ public void WhenReceivingAnIncorrectStringWithTheAbsenceOfASignTheTreeShouldThrowAnException()
+ {
+ Assert.Throws(() => tree.TreeExpression(" 1 2"));
+ }
+
+ [Test]
+ public void WhenReceivingAnIncorrectMoreDifficultStringWithTheAbsenceOfASignTheTreeShouldThrowAnException()
+ {
+ Assert.Throws(() => tree.TreeExpression("(* (4 5) 2)"));
+ }
+
+ [Test]
+ public void WhenReceivingAnIncorrectStringWithTheTheAbsenceOfANumberTheTreeShouldThrowAnException()
+ {
+ Assert.Throws(() => tree.TreeExpression("+ 2"));
+ }
+
+ [Test]
+ public void WhenReceivingAnIncorrectMoreDifficultStringWithTheTheAbsenceOfANumberTheTreeShouldThrowAnException()
+ {
+ Assert.Throws(() => tree.TreeExpression("(* (+ 2 3) )"));
+ }
+
+ [Test]
+ public void WhenReceivingAnDifficultStringWithInvalidCharactersTheTreeShouldThrowAnException()
+ {
+ Assert.Throws(() => tree.TreeExpression("(* (+ 2 3) p 2)"));
+ }
+
+ [Test]
+ public void WhenTryingToDivideByZeroTheTreeShouldThrowAnException()
+ {
+ tree.TreeExpression("/ 2 0");
+ Assert.Throws(() => tree.Calcuate());
+ }
+
+ [Test]
+ public void TheTreeShouldWorkCorrectlyWithNegativeNumbers()
+ {
+ tree.TreeExpression("+ 2 -3");
+ Assert.True(tree.Calcuate() == -1);
+ }
+}
\ No newline at end of file
diff --git a/ParsingTree/TestsForParsingTree/Usings.cs b/ParsingTree/TestsForParsingTree/Usings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/ParsingTree/TestsForParsingTree/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file