-
Notifications
You must be signed in to change notification settings - Fork 31
/
Interpreter.cs
145 lines (122 loc) · 4.82 KB
/
Interpreter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
namespace DesignPatterns.Behavioral;
public class Interpreter
{
/// <summary>
/// Client
/// </summary>
/// <remarks>
/// Build a syntax tree representing a particular sentence in the language that the grammar defines.
/// </remarks>
[Fact]
public void Execute()
{
var context = new Context();
// expression1 = 1 + 2
var expression1 = new AddExpression(new ConstantExpression(1), new ConstantExpression(2));
Assert.Equal(1 + 2, expression1.Solve(context));
// expression2 = 4 * 6
var expression2 = new MultiplyExpression(new ConstantExpression(4), new ConstantExpression(6));
Assert.Equal(4.0 * 6.0, expression2.Solve(context));
// expression3 = expression2 / 2
var expression3 = new DivideExpression(expression2, new ConstantExpression(2));
Assert.Equal(4.0 * 6.0 / 2.0, expression3.Solve(context));
// expression4 = expression1 - expression3
var expression4 = new SubtractExpression(new VariableExpression(nameof(expression1)), new VariableExpression(nameof(expression3)));
context.SetVariable(nameof(expression1), expression1);
context.SetVariable(nameof(expression3), expression3);
Assert.Equal( /* expression1 */1 + 2 - /* expression3 */4.0 * 6.0 / 2.0, expression4.Solve(context));
// f(x) = ((5 * x) / 2) + ((2 ^ x) - 6)
// x = 6
var expression5 = new AddExpression(
new DivideExpression(
new MultiplyExpression(
new ConstantExpression(5),
new VariableExpression("x")),
new ConstantExpression(2)),
new SubtractExpression(
new PowerExpression(
new ConstantExpression(2),
new VariableExpression("x")),
new ConstantExpression(6)));
double x = 6;
context.SetVariable("x", new ConstantExpression(x));
Assert.Equal(5 * x / 2 + (Math.Pow(2, x) - 6), expression5.Solve(context));
}
/// <summary>
/// Context
/// </summary>
/// <remarks>
/// Contains information that is global to the interpreter.
/// </remarks>
public class Context(params KeyValuePair<string, Expression>[] variables)
{
private readonly Dictionary<string, Expression> _variables = new(variables);
public void SetVariable(string variableName, Expression value)
{
_variables[variableName] = value;
}
public Expression GetVariable(string variableName)
{
return _variables[variableName];
}
}
/// <summary>
/// AbstractExpression.
/// </summary>
/// <remarks>
/// Declares an interface for executing an operation.
/// </remarks>
public abstract class Expression
{
public abstract double Solve(Context context);
}
/// <summary>
/// Non terminal expression
/// </summary>
public class AddExpression(Expression leftExpression, Expression rightExpression) : Expression
{
public override double Solve(Context context) => leftExpression.Solve(context) + rightExpression.Solve(context);
}
/// <summary>
/// Terminal expression
/// </summary>
public class ConstantExpression(double number) : Expression
{
public override double Solve(Context context) => number;
}
/// <summary>
/// Non terminal expression
/// </summary>
public class DivideExpression(Expression leftExpression, Expression rightExpression) : Expression
{
public override double Solve(Context context) => leftExpression.Solve(context) / rightExpression.Solve(context);
}
/// <summary>
/// Non terminal expression
/// </summary>
public class MultiplyExpression(Expression leftExpression, Expression rightExpression) : Expression
{
public override double Solve(Context context) => leftExpression.Solve(context) * rightExpression.Solve(context);
}
/// <summary>
/// Non terminal expression
/// </summary>
public class PowerExpression(Expression leftExpression, Expression rightExpression) : Expression
{
public override double Solve(Context context) => Math.Pow(leftExpression.Solve(context), rightExpression.Solve(context));
}
/// <summary>
/// Non terminal expression
/// </summary>
public class SubtractExpression(Expression leftExpression, Expression rightExpression) : Expression
{
public override double Solve(Context context) => leftExpression.Solve(context) - rightExpression.Solve(context);
}
/// <summary>
/// Non terminal expression
/// </summary>
public class VariableExpression(string variableName) : Expression
{
public override double Solve(Context context) => context.GetVariable(variableName).Solve(context);
}
}