diff --git a/ParseTree/ParseTree.Src/Exceptions/IncorrectExpressionExcpeption.cs b/ParseTree/ParseTree.Src/Exceptions/IncorrectExpressionExcpeption.cs
new file mode 100644
index 0000000..773716f
--- /dev/null
+++ b/ParseTree/ParseTree.Src/Exceptions/IncorrectExpressionExcpeption.cs
@@ -0,0 +1,7 @@
+namespace ParseTree;
+
+public class IncorrectExpressionException: Exception
+{
+ public IncorrectExpressionException() : base() { }
+ public IncorrectExpressionException(string message) : base(message) { }
+}
diff --git a/ParseTree/ParseTree.Src/Exceptions/IncorrectTreeException.cs b/ParseTree/ParseTree.Src/Exceptions/IncorrectTreeException.cs
new file mode 100644
index 0000000..00a15bd
--- /dev/null
+++ b/ParseTree/ParseTree.Src/Exceptions/IncorrectTreeException.cs
@@ -0,0 +1,7 @@
+namespace ParseTree;
+
+public class IncorrectTreeException: Exception
+{
+ public IncorrectTreeException() : base() { }
+ public IncorrectTreeException(string message) : base(message) { }
+}
diff --git a/ParseTree/ParseTree.Src/Nodes/INode.cs b/ParseTree/ParseTree.Src/Nodes/INode.cs
new file mode 100644
index 0000000..1e80536
--- /dev/null
+++ b/ParseTree/ParseTree.Src/Nodes/INode.cs
@@ -0,0 +1,12 @@
+using System.Data;
+
+namespace ParseTree.Dependencies;
+
+internal interface INode
+{
+ double Eval();
+ string ToString();
+
+ INode? LeftChild { get; set; }
+ INode? RightChild { get; set; }
+}
\ No newline at end of file
diff --git a/ParseTree/ParseTree.Src/Nodes/NumberNode.cs b/ParseTree/ParseTree.Src/Nodes/NumberNode.cs
new file mode 100644
index 0000000..2df52b6
--- /dev/null
+++ b/ParseTree/ParseTree.Src/Nodes/NumberNode.cs
@@ -0,0 +1,24 @@
+namespace ParseTree.Dependencies;
+
+internal class NumberNode : INode
+{
+ public double Eval()
+ {
+ return Value;
+ }
+
+ public override string ToString()
+ {
+ return Value.ToString();
+ }
+
+ public NumberNode(int value)
+ {
+ Value = value;
+ LeftChild = null;
+ }
+
+ public INode? LeftChild { get; set; }
+ public INode? RightChild { get; set; }
+ public double Value;
+}
diff --git a/ParseTree/ParseTree.Src/Nodes/OperationNode.cs b/ParseTree/ParseTree.Src/Nodes/OperationNode.cs
new file mode 100644
index 0000000..26a1137
--- /dev/null
+++ b/ParseTree/ParseTree.Src/Nodes/OperationNode.cs
@@ -0,0 +1,31 @@
+namespace ParseTree.Dependencies;
+
+internal class OperationNode : INode
+{
+ public INode? LeftChild { get; set; }
+ public INode? RightChild { get; set; }
+ public char operation;
+
+ public OperationNode(char operationChar)
+ {
+ operation = operationChar;
+ }
+
+ public double Eval()
+ {
+ if (LeftChild is not null && RightChild is not null)
+ {
+ return Operation.Calculate(operation, LeftChild.Eval(), RightChild.Eval());
+ }
+ throw new IncorrectTreeException();
+ }
+
+ public override string ToString()
+ {
+ if (LeftChild is not null && RightChild is not null)
+ {
+ return $"({operation} {LeftChild.ToString()} {RightChild.ToString()})";
+ }
+ throw new IncorrectTreeException();
+ }
+}
diff --git a/ParseTree/ParseTree.Src/Operation.cs b/ParseTree/ParseTree.Src/Operation.cs
new file mode 100644
index 0000000..b5b2174
--- /dev/null
+++ b/ParseTree/ParseTree.Src/Operation.cs
@@ -0,0 +1,49 @@
+using System.Runtime.InteropServices;
+
+namespace ParseTree.Dependencies;
+
+///
+/// Class implementing arithmetic operations based on char input
+///
+class Operation
+{
+ ///
+ /// Do the arithmetic operation corresponding to char
+ ///
+ /// Char '*', '+', '-' or '/'
+ /// Left operand
+ /// Right operand
+ /// Result of the operation
+ /// Thrown if operandRight is 0 and operation is '/'
+ /// thrown if argument operation is something different to '*', '+', '-' or '/'
+ public static double Calculate(char operation, double operandLeft, double operandRight)
+ {
+ switch (operation)
+ {
+ case '+':
+ {
+ return operandLeft + operandRight;
+ }
+ case '-':
+ {
+ return operandLeft - operandRight;
+ }
+ case '*':
+ {
+ return operandLeft * operandRight;
+ }
+ case '/':
+ {
+ if (operandRight == 0)
+ {
+ throw new DivideByZeroException();
+ }
+ return operandLeft / operandRight;
+ }
+ default:
+ {
+ throw new IncorrectExpressionException();
+ }
+ }
+ }
+}
diff --git a/ParseTree/ParseTree.Src/ParseTree.csproj b/ParseTree/ParseTree.Src/ParseTree.csproj
new file mode 100644
index 0000000..206b89a
--- /dev/null
+++ b/ParseTree/ParseTree.Src/ParseTree.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/ParseTree/ParseTree.Src/Program.cs b/ParseTree/ParseTree.Src/Program.cs
new file mode 100644
index 0000000..5b92bd9
--- /dev/null
+++ b/ParseTree/ParseTree.Src/Program.cs
@@ -0,0 +1,132 @@
+using System.Linq.Expressions;
+using ParseTree;
+
+string options = """
+ 0 - Exit
+ 1 - Create tree
+ 2 - Evaluate tree
+ 3 - Save tree to file
+ 4 - Print expression
+ Write number to console to choose option:
+ """;
+bool running = true;
+Tree? currentTree = null;
+while (running)
+{
+ Console.WriteLine(options);
+ int userInput;
+ while (!int.TryParse(Console.ReadLine(), out userInput) || userInput > 4 || userInput < 0)
+ {
+ Console.WriteLine("Incorrect input");
+ Console.WriteLine(options);
+ }
+
+ switch (userInput)
+ {
+ case 0:
+ {
+ Console.Write("Exit");
+ running = false;
+ break;
+ }
+ case 1:
+ {
+ Console.WriteLine("Write your ariphmetical expression in postfix form to console");
+ string? expression = Console.ReadLine();
+ try
+ {
+ if (expression is not null)
+ {
+ currentTree = new(expression);
+ }
+ }
+ catch (IncorrectExpressionException)
+ {
+ Console.WriteLine("Incorrect input\nYour expression must fit the template ( ) where operands may be expressions themselves");
+ }
+ break;
+ }
+ case 2:
+ {
+ try
+ {
+ if (currentTree is not null)
+ {
+ var answer = currentTree.Evaluate();
+ Console.WriteLine($"Answer to your expression is {answer}");
+ }
+ else
+ {
+ Console.WriteLine("You haven't added an expression yet");
+ }
+ }
+ catch (IncorrectExpressionException)
+ {
+ Console.WriteLine("Seems like your expression was incorrect. Please write another one");
+ }
+ catch (IncorrectTreeException)
+ {
+ Console.WriteLine("Seems like there is a problem with your tree");
+ }
+ break;
+ }
+ case 3:
+ {
+ Console.WriteLine("Write name for the file where you want to save your expression");
+ if (currentTree is not null)
+ {
+ string? filename = Console.ReadLine();
+ if (filename is not null && filename != string.Empty)
+ {
+ if (filename[0] != '/' || filename[0] != '~' || filename[0] != '.')
+ {
+ filename = "./" + filename;
+ }
+ try
+ {
+ string? expression = currentTree.ToString();
+ File.WriteAllText(filename, expression);
+ Console.Write("Your expression was saved at ");
+ Console.WriteLine(filename);
+ }
+ catch (IncorrectTreeException)
+ {
+ Console.WriteLine("Seems like there is a problem with your tree");
+ }
+
+ }
+ else
+ {
+ Console.WriteLine("You should write a filename for your file");
+ }
+ }
+ else
+ {
+ Console.WriteLine("You haven't added an expression yet");
+ }
+ break;
+ }
+ case 4:
+ {
+ if (currentTree is not null)
+ {
+ try
+ {
+ string? expression = currentTree.ToString();
+ Console.Write("Your expression: ");
+ Console.WriteLine(expression);
+ }
+ catch (IncorrectTreeException)
+ {
+ Console.WriteLine("Seems like there is a problem with your tree");
+ }
+ }
+ else
+ {
+ Console.WriteLine("You haven't added an expression yet");
+ }
+ break;
+ }
+ }
+ Console.WriteLine();
+}
diff --git a/ParseTree/ParseTree.Src/Tree.cs b/ParseTree/ParseTree.Src/Tree.cs
new file mode 100644
index 0000000..50f3452
--- /dev/null
+++ b/ParseTree/ParseTree.Src/Tree.cs
@@ -0,0 +1,118 @@
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq.Expressions;
+using ParseTree.Dependencies;
+
+namespace ParseTree;
+
+///
+/// Data structure for storing ariphmetical expressions
+///
+public class Tree
+{
+ private INode root;
+
+ public Tree(string expression)
+ {
+ if (expression is null || expression == string.Empty)
+ {
+ throw new IncorrectExpressionException("Empty expression");
+ }
+
+ int index = 0;
+ SkipSpaces(expression, ref index);
+ if (expression[index] >= '0' && expression[index] <= '9')
+ {
+ int number = ParseNumber(expression, ref index);
+ if (index != expression.Length)
+ {
+ throw new IncorrectExpressionException();
+ }
+ root = new NumberNode(number);
+ }
+ else
+ {
+ root = Parse(expression, ref index);
+ }
+ }
+
+ private static INode Parse(string expression, ref int index)
+ {
+ INode newNode;
+ SkipSpaces(expression, ref index);
+ char currentChar = expression[index];
+ if (currentChar == '(')
+ {
+ ++index;
+ SkipSpaces(expression, ref index);
+ newNode = new OperationNode(expression[index]);
+ ++index;
+ newNode.LeftChild = Parse(expression, ref index);
+ newNode.RightChild = Parse(expression, ref index);
+ SkipSpaces(expression, ref index);
+ if (expression[index] == ')')
+ {
+ ++index;
+ }
+ else
+ {
+ throw new IncorrectExpressionException();
+ }
+ }
+ else if (currentChar >= '0' && currentChar <= '9')
+ {
+ int number = ParseNumber(expression, ref index);
+ newNode = new NumberNode(number);
+ }
+ else
+ {
+ throw new IncorrectExpressionException();
+ }
+
+ return newNode;
+ }
+
+ private static void SkipSpaces(string expression, ref int index)
+ {
+ while (expression[index] == ' ')
+ {
+ ++index;
+ }
+ }
+
+ private static int ParseNumber(string expression, ref int index)
+ {
+ int currentNumber = 0;
+ char currentChar = expression[index];
+ while (currentChar >= '0' && currentChar <= '9')
+ {
+ currentNumber *= 10;
+ currentNumber += expression[index] - '0';
+ ++index;
+ if (currentChar >= expression.Length)
+ {
+ break;
+ }
+ currentChar = expression[index];
+ }
+ return currentNumber;
+ }
+
+ ///
+ /// Evaluate the expression stored in the tree
+ ///
+ /// Answer to expression
+ public double Evaluate()
+ {
+ return root.Eval();
+ }
+
+ ///
+ /// Write the expression in postfix form to string
+ ///
+ ///
+ public override string ToString()
+ {
+ return root.ToString();
+ }
+}
diff --git a/ParseTree/ParseTree.Tests/ParseTree.Tests.cs b/ParseTree/ParseTree.Tests/ParseTree.Tests.cs
new file mode 100644
index 0000000..f51bf49
--- /dev/null
+++ b/ParseTree/ParseTree.Tests/ParseTree.Tests.cs
@@ -0,0 +1,39 @@
+namespace ParseTree.Tests;
+
+using System.Data;
+using ParseTree;
+
+public class Tests
+{
+ [TestCase("( * (+ 1 1 ) 2 )", 4)]
+ [TestCase("5", 5)]
+ [TestCase("(/ 5 2)", 2.5)]
+ public void TestEvaluation(string expression, double expectedResult)
+ {
+ var tree = new Tree(expression);
+ double result = tree.Evaluate();
+
+ Assert.That(result, Is.EqualTo(expectedResult));
+ }
+
+ [TestCase("")]
+ [TestCase("]")]
+ [TestCase("7 7")]
+ [TestCase("+ 5 5")]
+ public void IncorrectInputTest(string expression)
+ {
+ Assert.Throws(() => new Tree(expression));
+ }
+
+ [TestCase("(* (+ 1 1) 2)")]
+ [TestCase("5")]
+ [TestCase("(/ 5 2)")]
+ public void ToStringTests(string expression)
+ {
+ var tree = new Tree(expression);
+ var result = tree.ToString();
+
+ Assert.That(result, Is.EqualTo(expression));
+ }
+}
+
\ No newline at end of file
diff --git a/ParseTree/ParseTree.Tests/ParseTree.Tests.csproj b/ParseTree/ParseTree.Tests/ParseTree.Tests.csproj
new file mode 100644
index 0000000..5d1d206
--- /dev/null
+++ b/ParseTree/ParseTree.Tests/ParseTree.Tests.csproj
@@ -0,0 +1,28 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ParseTree/ParseTree.sln b/ParseTree/ParseTree.sln
new file mode 100644
index 0000000..d8d211c
--- /dev/null
+++ b/ParseTree/ParseTree.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseTree", "ParseTree.Src\ParseTree.csproj", "{70E2E29F-DAE1-43F1-BF14-B9FB100883D5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParseTree.Tests", "ParseTree.Tests\ParseTree.Tests.csproj", "{908939E8-E73B-4C6E-A73B-A04188F9BE0A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {70E2E29F-DAE1-43F1-BF14-B9FB100883D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {70E2E29F-DAE1-43F1-BF14-B9FB100883D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {70E2E29F-DAE1-43F1-BF14-B9FB100883D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {70E2E29F-DAE1-43F1-BF14-B9FB100883D5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {908939E8-E73B-4C6E-A73B-A04188F9BE0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {908939E8-E73B-4C6E-A73B-A04188F9BE0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {908939E8-E73B-4C6E-A73B-A04188F9BE0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {908939E8-E73B-4C6E-A73B-A04188F9BE0A}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal