Parser: Multiplication, division and parenthesis.

This commit is contained in:
2019-12-01 16:50:29 +01:00
parent 49941a7861
commit 0fe4e54bcb
8 changed files with 146 additions and 9 deletions

View File

@@ -5,6 +5,8 @@ namespace VAR.ExpressionEvaluator.Tests
[TestClass()] [TestClass()]
public class ParserTests public class ParserTests
{ {
#region Plus and Minus
[TestMethod()] [TestMethod()]
public void ParseString__Ten_EqualsTen() public void ParseString__Ten_EqualsTen()
{ {
@@ -37,6 +39,10 @@ namespace VAR.ExpressionEvaluator.Tests
Assert.AreEqual(900000m, result); Assert.AreEqual(900000m, result);
} }
#endregion Plus and minus
#region Number signs
[TestMethod()] [TestMethod()]
public void ParseString__MinusTen() public void ParseString__MinusTen()
{ {
@@ -77,5 +83,67 @@ namespace VAR.ExpressionEvaluator.Tests
Assert.AreEqual(-40m, result); Assert.AreEqual(-40m, result);
} }
#endregion Number signs
#region Multiplication and division
[TestMethod()]
public void ParseString__10MutiplyBy2()
{
string expression = "10 * 2";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(20m, result);
}
[TestMethod()]
public void ParseString__10DividedBy2()
{
string expression = "10 / 2";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(5m, result);
}
[TestMethod()]
public void ParseString__5DividedBy2()
{
string expression = "5 / 2";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(2.5m, result);
}
[TestMethod()]
public void ParseString__5DividedBy2Plus1()
{
string expression = "5 / 2 + 1";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(3.5m, result);
}
[TestMethod()]
public void ParseString__1Plus5DividedBy2()
{
string expression = "1 + 5 / 2";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(3.5m, result);
}
[TestMethod()]
public void ParseString__5DividedByParen1Plus1()
{
string expression = "5 / (1 + 1)";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(2.5m, result);
}
[TestMethod()]
public void ParseString__Paren2Plus2DividedByParen1Plus1()
{
string expression = "(2 + 2) / (1 + 1)";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(2m, result);
}
#endregion Multiplication and division
} }
} }

View File

@@ -120,7 +120,7 @@ namespace VAR.ExpressionEvaluator.Tests
var t = new Tokenizer(new StringReader(testString)); var t = new Tokenizer(new StringReader(testString));
// "(" // "("
Assert.AreEqual(t.Token, Token.ParentesisStart); Assert.AreEqual(t.Token, Token.ParenthesisStart);
t.NextToken(); t.NextToken();
// "10" // "10"
@@ -138,7 +138,7 @@ namespace VAR.ExpressionEvaluator.Tests
t.NextToken(); t.NextToken();
// ")" // ")"
Assert.AreEqual(t.Token, Token.ParentesisEnd); Assert.AreEqual(t.Token, Token.ParenthesisEnd);
t.NextToken(); t.NextToken();
// "*" // "*"

View File

@@ -0,0 +1,15 @@
namespace VAR.ExpressionEvaluator
{
public class ExpressionDivisionNode : ExpressionBinaryNode
{
public ExpressionDivisionNode(IExpressionNode leftNode, IExpressionNode rightNode) :
base(leftNode, rightNode, DivisionOp)
{
}
private static object DivisionOp(object leftValue, object rightValue)
{
return (decimal)leftValue / (decimal)rightValue;
}
}
}

View File

@@ -0,0 +1,15 @@
namespace VAR.ExpressionEvaluator
{
public class ExpressionMultiplyNode : ExpressionBinaryNode
{
public ExpressionMultiplyNode(IExpressionNode leftNode, IExpressionNode rightNode) :
base(leftNode, rightNode, MultiplyOp)
{
}
private static object MultiplyOp(object leftValue, object rightValue)
{
return (decimal)leftValue * (decimal)rightValue;
}
}
}

View File

@@ -26,19 +26,19 @@ namespace VAR.ExpressionEvaluator
public IExpressionNode ParsePlusAndMinus() public IExpressionNode ParsePlusAndMinus()
{ {
IExpressionNode leftNode = ParseUnary(); IExpressionNode leftNode = ParseMultiplyDivision();
while (true) while (true)
{ {
if (_tokenizer.Token == Token.Plus) if (_tokenizer.Token == Token.Plus)
{ {
_tokenizer.NextToken(); _tokenizer.NextToken();
IExpressionNode rightNode = ParseUnary(); IExpressionNode rightNode = ParseMultiplyDivision();
leftNode = new ExpressionPlusNode(leftNode, rightNode); leftNode = new ExpressionPlusNode(leftNode, rightNode);
} }
else if (_tokenizer.Token == Token.Minus) else if (_tokenizer.Token == Token.Minus)
{ {
_tokenizer.NextToken(); _tokenizer.NextToken();
IExpressionNode rightNode = ParseUnary(); IExpressionNode rightNode = ParseMultiplyDivision();
leftNode = new ExpressionMinusNode(leftNode, rightNode); leftNode = new ExpressionMinusNode(leftNode, rightNode);
} }
else else
@@ -48,6 +48,31 @@ namespace VAR.ExpressionEvaluator
} }
} }
private IExpressionNode ParseMultiplyDivision()
{
IExpressionNode lhs = ParseUnary();
while (true)
{
if (_tokenizer.Token == Token.Multiply)
{
_tokenizer.NextToken();
IExpressionNode rhs = ParseUnary();
lhs = new ExpressionMultiplyNode(lhs, rhs);
}
else if (_tokenizer.Token == Token.Division)
{
_tokenizer.NextToken();
IExpressionNode rhs = ParseUnary();
lhs = new ExpressionDivisionNode(lhs, rhs);
}
else
{
return lhs;
}
}
}
private IExpressionNode ParseUnary() private IExpressionNode ParseUnary()
{ {
if (_tokenizer.Token == Token.Plus) if (_tokenizer.Token == Token.Plus)
@@ -73,6 +98,18 @@ namespace VAR.ExpressionEvaluator
return node; return node;
} }
if (_tokenizer.Token == Token.ParenthesisStart)
{
_tokenizer.NextToken();
var node = ParsePlusAndMinus();
if (_tokenizer.Token != Token.ParenthesisEnd)
{
throw new Exception("Missing close parenthesis");
}
_tokenizer.NextToken();
return node;
}
throw new Exception(string.Format("Unexpected token: {0}", _tokenizer.Token.ToString())); throw new Exception(string.Format("Unexpected token: {0}", _tokenizer.Token.ToString()));
} }

View File

@@ -13,8 +13,8 @@
GreaterOrEqualThan, GreaterOrEqualThan,
LessThan, LessThan,
LessOrEqualThan, LessOrEqualThan,
ParentesisStart, ParenthesisStart,
ParentesisEnd, ParenthesisEnd,
Keyword, Keyword,
String, String,
Number, Number,

View File

@@ -93,12 +93,12 @@ namespace VAR.ExpressionEvaluator
case '(': case '(':
NextChar(); NextChar();
_currentToken = Token.ParentesisStart; _currentToken = Token.ParenthesisStart;
return; return;
case ')': case ')':
NextChar(); NextChar();
_currentToken = Token.ParentesisEnd; _currentToken = Token.ParenthesisEnd;
return; return;
case '=': case '=':

View File

@@ -41,6 +41,8 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ExpressionDivisionNode.cs" />
<Compile Include="ExpressionMultiplyNode.cs" />
<Compile Include="ExpressionUnaryNode.cs" /> <Compile Include="ExpressionUnaryNode.cs" />
<Compile Include="ExpressionBinaryNode.cs" /> <Compile Include="ExpressionBinaryNode.cs" />
<Compile Include="ExpressionMinusNode.cs" /> <Compile Include="ExpressionMinusNode.cs" />