diff --git a/VAR.ExpressionEvaluator.Tests/ParserTests.cs b/VAR.ExpressionEvaluator.Tests/ParserTests.cs
new file mode 100644
index 0000000..e2b348b
--- /dev/null
+++ b/VAR.ExpressionEvaluator.Tests/ParserTests.cs
@@ -0,0 +1,40 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace VAR.ExpressionEvaluator.Tests
+{
+ [TestClass()]
+ public class ParserTests
+ {
+ [TestMethod()]
+ public void ParseString__Ten_EqualsTen()
+ {
+ string expression = "10";
+ object result = Parser.EvaluateString(expression);
+ Assert.AreEqual(10m, result);
+ }
+
+ [TestMethod()]
+ public void ParseString__OnePlusTwo_EqualsThree()
+ {
+ string expression = "1 + 2";
+ object result = Parser.EvaluateString(expression);
+ Assert.AreEqual(3m, result);
+ }
+
+ [TestMethod()]
+ public void ParseString__OneMinusTwo_EqualsMinusOne()
+ {
+ string expression = "1 - 2";
+ object result = Parser.EvaluateString(expression);
+ Assert.AreEqual(-1m, result);
+ }
+
+ [TestMethod()]
+ public void ParseString__OneMillionMinusHundredThousands_EqualsNineHundredThousands()
+ {
+ string expression = "1000000 - 100000";
+ object result = Parser.EvaluateString(expression);
+ Assert.AreEqual(900000m, result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/VAR.ExpressionEvaluator.Tests/VAR.ExpressionEvaluator.Tests.csproj b/VAR.ExpressionEvaluator.Tests/VAR.ExpressionEvaluator.Tests.csproj
index b0f1dfe..0c66a37 100644
--- a/VAR.ExpressionEvaluator.Tests/VAR.ExpressionEvaluator.Tests.csproj
+++ b/VAR.ExpressionEvaluator.Tests/VAR.ExpressionEvaluator.Tests.csproj
@@ -54,6 +54,7 @@
+
diff --git a/VAR.ExpressionEvaluator/ExpressionMinusNode.cs b/VAR.ExpressionEvaluator/ExpressionMinusNode.cs
new file mode 100644
index 0000000..30e0c81
--- /dev/null
+++ b/VAR.ExpressionEvaluator/ExpressionMinusNode.cs
@@ -0,0 +1,15 @@
+namespace VAR.ExpressionEvaluator
+{
+ public class ExpressionMinusNode : ExpressionBinaryNode
+ {
+ public ExpressionMinusNode(IExpressionNode leftNode, IExpressionNode rightNode) :
+ base(leftNode, rightNode, MinusOp)
+ {
+ }
+
+ private static object MinusOp(object leftValue, object rightValue)
+ {
+ return (decimal)leftValue - (decimal)rightValue;
+ }
+ }
+}
diff --git a/VAR.ExpressionEvaluator/ExpressionPlusNode.cs b/VAR.ExpressionEvaluator/ExpressionPlusNode.cs
new file mode 100644
index 0000000..9adb6c3
--- /dev/null
+++ b/VAR.ExpressionEvaluator/ExpressionPlusNode.cs
@@ -0,0 +1,15 @@
+namespace VAR.ExpressionEvaluator
+{
+ public class ExpressionPlusNode : ExpressionBinaryNode
+ {
+ public ExpressionPlusNode(IExpressionNode leftNode, IExpressionNode rightNode) :
+ base(leftNode, rightNode, PlusOp)
+ {
+ }
+
+ private static object PlusOp(object leftValue, object rightValue)
+ {
+ return (decimal)leftValue + (decimal)rightValue;
+ }
+ }
+}
diff --git a/VAR.ExpressionEvaluator/Parser.cs b/VAR.ExpressionEvaluator/Parser.cs
new file mode 100644
index 0000000..922f3fd
--- /dev/null
+++ b/VAR.ExpressionEvaluator/Parser.cs
@@ -0,0 +1,77 @@
+using System;
+using System.IO;
+
+namespace VAR.ExpressionEvaluator
+{
+ public class Parser
+ {
+ private ITokenizer _tokenizer;
+
+ public Parser(ITokenizer tokenizer)
+ {
+ _tokenizer = tokenizer;
+ }
+
+ public IExpressionNode ParseExpression()
+ {
+ var expr = ParsePlusAndMinus();
+
+ if (_tokenizer.Token != Token.EOF)
+ {
+ throw new Exception("Unexpected characters at end of expression");
+ }
+
+ return expr;
+ }
+
+ public IExpressionNode ParsePlusAndMinus()
+ {
+ IExpressionNode leftNode = ParseTerminus();
+ while (true)
+ {
+ if (_tokenizer.Token == Token.Plus)
+ {
+ _tokenizer.NextToken();
+ IExpressionNode rightNode = ParseTerminus();
+ leftNode = new ExpressionPlusNode(leftNode, rightNode);
+ }
+ else if (_tokenizer.Token == Token.Minus)
+ {
+ _tokenizer.NextToken();
+ IExpressionNode rightNode = ParseTerminus();
+ leftNode = new ExpressionMinusNode(leftNode, rightNode);
+ }
+ else
+ {
+ return leftNode;
+ }
+ }
+ }
+
+ private IExpressionNode ParseTerminus()
+ {
+ if (_tokenizer.Token == Token.Number)
+ {
+ var node = new ExpressionNumberNode(_tokenizer.Number ?? 0m);
+ _tokenizer.NextToken();
+ return node;
+ }
+
+ throw new Exception(string.Format("Unexpected token: {0}", _tokenizer.Token.ToString()));
+ }
+
+ public static IExpressionNode ParseString(string str)
+ {
+ TextReader textReader = new StringReader(str);
+ ITokenizer tokenizer = new Tokenizer(textReader);
+ Parser parser = new Parser(tokenizer);
+ return parser.ParseExpression();
+ }
+
+ public static object EvaluateString(string str)
+ {
+ IExpressionNode node = ParseString(str);
+ return node.Eval();
+ }
+ }
+}
diff --git a/VAR.ExpressionEvaluator/VAR.ExpressionEvaluator.csproj b/VAR.ExpressionEvaluator/VAR.ExpressionEvaluator.csproj
index 6495ec0..cbd95dd 100644
--- a/VAR.ExpressionEvaluator/VAR.ExpressionEvaluator.csproj
+++ b/VAR.ExpressionEvaluator/VAR.ExpressionEvaluator.csproj
@@ -42,10 +42,13 @@
+
+
+