-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCalculator.cs
138 lines (125 loc) · 4.75 KB
/
Calculator.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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Лабораторная_работа__6
{
interface ICallable
{
object Call(params object[] args);
}
class DumpFunction : ICallable
{
public object Call(params object[] args)
{
Console.WriteLine(string.Join(" ", args.Select(x => x ?? "null")));
return this;
}
}
interface IExpressionVisitor
{
object Visit(BinaryOperation expression);
object Visit(UnaryOperation expression);
object Visit(CallExpression expression);
object Visit(Paren expression);
object Visit(Number expression);
object Visit(Identifier expression);
}
class Calculator : IExpressionVisitor
{
static readonly IReadOnlyDictionary<string, object> constants = new Dictionary<string, object>() {
{ "true", true },
{ "false", false },
{ "null", null },
{ "dump", new DumpFunction() }
};
public Dictionary<string, object> variables;
public Calculator(Dictionary<string, object> variables)
{
this.variables = variables.Concat(constants.Where(x => !variables.ContainsKey(x.Key))).ToDictionary(x => x.Key, x => x.Value);
}
object Calc(IExpression expression) => expression.Accept(this);
public object Visit(BinaryOperation expression)
{
var left = Calc(expression.Left);
var right = Calc(expression.Right);
if (left is null || right is null)
{
switch (expression.Operation)
{
case OperationType.Equality:
return left == right;
}
throw new Exception("Неизвестная операция");
}
if (left is int && right is int)
{
int leftInt = (int)left;
int rightInt = (int)right;
switch (expression.Operation)
{
case OperationType.Addition:
return leftInt + rightInt;
case OperationType.Subtraction:
return leftInt - rightInt;
case OperationType.Multiplication:
return leftInt * rightInt;
case OperationType.Division:
return leftInt / rightInt;
case OperationType.Remainder:
return leftInt % rightInt;
case OperationType.Equality:
return leftInt == rightInt;
case OperationType.Relation:
return leftInt < rightInt;
}
throw new Exception("Неизвестная операция");
}
if (left is bool && right is bool)
{
bool leftBool = (bool)left;
bool rightBool = (bool)right;
switch (expression.Operation)
{
case OperationType.Equality:
return leftBool == rightBool;
case OperationType.Relation:
return (!leftBool && rightBool);
}
throw new Exception("Неизвестная операция");
}
throw new Exception("Неверный тип операндов");
}
public object Visit(UnaryOperation expression)
{
switch (expression.Operation)
{
case OperationType.UnaryMinus:
return -(int)Calc(expression.Expression);
case OperationType.LogicalNegation:
return !(bool)Calc(expression.Expression);
}
throw new Exception("Неизвестная операция");
}
public object Visit(Paren expression) => Calc(expression.Value);
public object Visit(CallExpression expression)
{
var function = Calc(expression.Function);
if(function is ICallable)
{
return ((ICallable)function).Call(expression.Arguments.Select(x => Calc(x)).ToArray());
}
throw new Exception("Вызвали не функцию");
}
public object Visit(Number expression) => int.Parse(expression.Token.Lexeme);
public object Visit(Identifier expression)
{
if (variables.TryGetValue(expression.Value, out object value))
{
return value;
}
throw new Exception("Неизвестная переменная");
}
}
}