Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculation expression #9

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
31 changes: 31 additions & 0 deletions Homework4/ParsingTree/ParsingTree.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32228.430
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParsingTree", "ParsingTree\ParsingTree.csproj", "{3A685608-3E27-4534-942C-AE951EF76977}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestParsingTree", "TestParsingTree\TestParsingTree.csproj", "{921D199E-504F-47CD-AC97-9C93A98C8B0D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3A685608-3E27-4534-942C-AE951EF76977}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A685608-3E27-4534-942C-AE951EF76977}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A685608-3E27-4534-942C-AE951EF76977}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A685608-3E27-4534-942C-AE951EF76977}.Release|Any CPU.Build.0 = Release|Any CPU
{921D199E-504F-47CD-AC97-9C93A98C8B0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{921D199E-504F-47CD-AC97-9C93A98C8B0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{921D199E-504F-47CD-AC97-9C93A98C8B0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{921D199E-504F-47CD-AC97-9C93A98C8B0D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DD0BE32A-1D93-45E3-ACD3-92A75D23D824}
EndGlobalSection
EndGlobal
296 changes: 296 additions & 0 deletions Homework4/ParsingTree/ParsingTree/ParsingTree.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
namespace ParsingTree;

using System;

/// <summary>
/// Class representing the parse tree
/// </summary>
public class ParsingTree
{
/// <summary>
/// abstract nested class for dividing node into operators and operands for building a parse tree

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Везде с заглавной, а тут со строчной, неконсистентно

/// </summary>
private abstract class Node
{
// Abstract method for counting each operator or operand
public abstract float Count();

// Abstract method for printing each operator or operand
public abstract void Print();

/// <summary>
/// A class representing operands
/// </summary>
public class Operand : Node

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Operand не должен быть по идее вложенным в Node, потому что а зачем :) Пусть он будет вложенным в ParsingTree

{
private readonly string Value;
public Operand(string element)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private readonly string Value;
public Operand(string element)
private readonly string Value;
public Operand(string element)

{
Value = element;
}

// The operand class calculates the value for them and returns it

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Комментарии с // используются только для комментариев внутри методов, тут бы ///
Но можно /// <inheritdoc /> — что комментарий наследуется от предка

public override float Count()
{
return float.Parse(Value);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public override float Count()
{
return float.Parse(Value);
}
public override float Count()
=> float.Parse(Value);


// The operand class can print the values of operands
public override void Print()
{
Console.Write(Value);
Console.Write(" ");
}
}

/// <summary>
/// A class representing operators
/// </summary>
public abstract class Operator : Node
{
// Each operator , unlike an operand, has a right and a left son
public Node? LeftSon;
public Node? RightSon;

// There will be only 4 operators, so the value field does not make sense

// Template for printing operators
public void OperatorPrintTemplate(string symbol)
{
Console.Write("(");
Console.Write(symbol);
LeftSon?.Print();
RightSon?.Print();
Console.Write(")");
}

// A class representing the operator +
public class Plus : Operator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Три уровня вложенности, ужас. Нет, надо, чтобы они все были на одном уровне и вложенными в ParseTree сам.

{
public override float Count()
{
if (LeftSon == null || RightSon == null)
{
throw new NullReferenceException();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нельзя NullReferenceException кидать, оно кидается .NET-машиной

}

return LeftSon.Count() + RightSon.Count();
}

public override void Print()
{
if (LeftSon == null || RightSon == null)
{
return;
}

OperatorPrintTemplate("+");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это известный антипаттерн "Вызов предка" (Call super). Лучше было наоборот, Print перегрузить в Operator, и чтобы он дёргал, например, свойство Symbol, которое было бы разным у каждого оператора. Иначе где-то забудете вызвать OperatorPrintTemplate, и будет беда

}
}

// A class representing the operator -
public class Minus : Operator
{
public override float Count()
{
if (LeftSon == null || RightSon == null)
{
throw new NullReferenceException();
}

return LeftSon.Count() - RightSon.Count();
}

public override void Print()
{
if (LeftSon == null || RightSon == null)
{
return;
}

OperatorPrintTemplate("-");
}
}

// A class representing the operator /
public class Divide : Operator
{
public override float Count()
{
if (LeftSon == null || RightSon == null)
{
throw new NullReferenceException();
}

float rightSonValue = RightSon.Count();
if (Math.Abs(rightSonValue - 0) < 0.0000000000000000000000000001)
{
throw new DivideByZeroException();
}

return LeftSon.Count() / rightSonValue;
}

public override void Print()
{
if (LeftSon == null || RightSon == null)
{
return;
}

OperatorPrintTemplate("/");
}
}

// A class representing the operator *
public class Multiplication : Operator
{
public override float Count()
{
if (LeftSon == null || RightSon == null)
{
throw new NullReferenceException();
}
return LeftSon.Count() * RightSon.Count();
}

public override void Print()
{
if (LeftSon == null || RightSon == null)
{
return;
}
OperatorPrintTemplate("*");
}
}
}
}

Node? treeRoot;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Node? treeRoot;
private Node? treeRoot;


/// <summary>
/// Function for building a tree
/// </summary>
/// <param name="expression">The expression that needs to be calculated</param>
public void BuildTree(string expression)
{
int index = 0;
Node? node = null;
treeRoot = PrivateBuildTree(expression, ref index, node);
}

// Auxiliary function for building a tree

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

///

private Node? PrivateBuildTree(string expression, ref int index, Node? node)
{
if (index >= expression.Length)
{
return node;
}

// Skip the characters we don't need
while (expression[index] == '(' || expression[index] == ')' || expression[index] == ' ' && index < expression.Length)
{
index++;
}

// The condition in order to avoid confusion, for example, with 4 -5 and 4 - 5
if (index < expression.Length - 1 && !IsOperand(expression[index + 1]) && IsOperator(expression[index]))
{
InitializeNode(expression, ref index, ref node);
return node;
}

// The number could be negative
int newIndex = expression[index] == '-' ? index + 1 : index;
string nodeValue = "";
while (newIndex < expression.Length && IsOperand(expression[newIndex]))
{
nodeValue += expression[newIndex];
newIndex++;
}
Node? newNode = null;

//This unused variable x is needed in order to call the function,
//and it is the operand that is initialized,
//because the last character of the number cannot be an operator (the file is considered correct

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//This unused variable x is needed in order to call the function,
//and it is the operand that is initialized,
//because the last character of the number cannot be an operator (the file is considered correct
// This unused variable x is needed in order to call the function,
// and it is the operand that is initialized,
// because the last character of the number cannot be an operator (the file is considered correct

int x = nodeValue.Length - 1;
if (expression[index] == '-')
{
InitializeNode("-" + nodeValue, ref x, ref newNode);
}
else
{
InitializeNode(nodeValue, ref x, ref newNode);
}
index = newIndex;
return newNode;
}

// A function for initializing nodes depending on which operator or operator is a string
private void InitializeNode(string expression, ref int index, ref Node? node)
{
switch (expression[index])
{
case '+':
{
node = new Node.Operator.Plus();
index++;
((Node.Operator.Plus)node).LeftSon = PrivateBuildTree(expression, ref index, ((Node.Operator.Plus)node).LeftSon);
((Node.Operator.Plus)node).RightSon = PrivateBuildTree(expression, ref index, ((Node.Operator.Plus)node).RightSon);
return;
}
case '-':
{
node = new Node.Operator.Minus();
index++;
((Node.Operator.Minus)node).LeftSon = PrivateBuildTree(expression, ref index, ((Node.Operator.Minus)node).LeftSon);
((Node.Operator.Minus)node).RightSon = PrivateBuildTree(expression, ref index, ((Node.Operator.Minus)node).RightSon);
return;
}
case '*':
{
node = new Node.Operator.Multiplication();
index++;
((Node.Operator.Multiplication)node).LeftSon = PrivateBuildTree(expression, ref index, ((Node.Operator.Multiplication)node).LeftSon);
((Node.Operator.Multiplication)node).RightSon = PrivateBuildTree(expression, ref index, ((Node.Operator.Multiplication)node).RightSon);
return;
}
case '/':
{
node = new Node.Operator.Divide();
index++;
((Node.Operator.Divide)node).LeftSon = PrivateBuildTree(expression, ref index, ((Node.Operator.Divide)node).LeftSon);
((Node.Operator.Divide)node).RightSon = PrivateBuildTree(expression, ref index, ((Node.Operator.Divide)node).RightSon);
return;
}
default:
{
node = new Node.Operand(expression);
index++;
return;
}
}
}

/// <summary>
/// Function for printing a tree
/// </summary>
public void Print() => treeRoot?.Print();

/// <summary>
/// Function for calculating the value of an expression
/// </summary>
/// <returns>value of an expression</returns>
public float Count()
{
if (treeRoot == null)
{
throw new NullReferenceException();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:(
Тут InvalidOperationException — объект не в том состоянии, чтобы обработать запрос, хотя сам запрос и корректен.

}
return treeRoot.Count();
}

private static bool IsOperator(char element) => element == '+' || element == '-' || element == '*' || element == '/';

private static bool IsOperand(char element) => element <= '9' && element >= '0';
}
10 changes: 10 additions & 0 deletions Homework4/ParsingTree/ParsingTree/ParsingTree.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
25 changes: 25 additions & 0 deletions Homework4/ParsingTree/ParsingTree/ParsingTreeInterface.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace ParsingTree;

/// <summary>
/// Parse Tree Interface
/// </summary>
public interface IParsingTree

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Он у Вас нигде не используется, следовательно не нужен

{

/// <summary>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{
/// <summary>
{
/// <summary>

/// Function for printing a tree
/// </summary>
public void Print();

/// <summary>
/// Function for building a tree
/// </summary>
/// <param name="expression">The expression on the basis of which the tree is built</param>
public void BuildTree(string expression);

/// <summary>
/// Function for calculating the value of an expression
/// </summary>
/// <returns>value of an expression</returns>
public float Count();
}
1 change: 1 addition & 0 deletions Homework4/ParsingTree/TestParsingTree/FirstTest.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(* (+ 1 1) 2)
Loading