-
Notifications
You must be signed in to change notification settings - Fork 119
/
Copy pathParse Lisp Expression.cpp
118 lines (118 loc) · 3.48 KB
/
Parse Lisp Expression.cpp
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
class Context {
unordered_map<string_view, int> _map;
const Context *_parent{};
public:
Context(const Context *parent) : _parent{parent}
{
;
}
const Context* Parent() const { return _parent; }
int GetValue(const string_view &key) const
{
auto it = _map.find(key);
if (it != _map.end()) return it->second;
if (_parent) return _parent->GetValue(key);
assert(0);
return numeric_limits<int>::min();
}
void AddValue(const string_view &key, int val) {
auto [it, isInserted] = _map.emplace(key, val);
if (!isInserted) it->second = val;
}
};
class Solution {
string_view symbol(string_view &expr) {
string_view ret;
if (expr.empty() || !isalpha(expr[0])) {
return ret;
}
auto pos = expr.find_first_of(" )");
assert(pos != string_view::npos);
ret = expr.substr(0, pos);
expr.remove_prefix(pos);
return ret;
}
int evaluate(string_view &expr, Context *context) {
assert(!expr.empty());
if (expr[0] == '(') {
assert(expr.length() >= 4);
if (expr.substr(0, 4) == "(add") {
assert(expr.length() > 4);
expr.remove_prefix(4);
assert(!expr.empty() && expr[0] == ' ');
expr.remove_prefix(1);
int l = evaluate(expr, context);
assert(!expr.empty() && expr[0] == ' ');
expr.remove_prefix(1);
int r = evaluate(expr, context);
assert(!expr.empty() && expr[0] == ')');
expr.remove_prefix(1);
return l + r;
}
if (expr.substr(0, 4) == "(mul") {
assert(expr.length() > 5);
expr.remove_prefix(5);
assert(!expr.empty() && expr[0] == ' ');
expr.remove_prefix(1);
int l = evaluate(expr, context);
assert(!expr.empty() && expr[0] == ' ');
expr.remove_prefix(1);
int r = evaluate(expr, context);
assert(!expr.empty() && expr[0] == ')');
expr.remove_prefix(1);
return l * r;
}
if (expr.substr(0, 4) == "(let") {
assert(expr.length() > 4);
expr.remove_prefix(4);
Context nc(context);
while (1) {
assert(!expr.empty() && expr[0] == ' ');
expr.remove_prefix(1);
string_view sym = symbol(expr);
assert(!expr.empty());
if (sym.empty() || expr[0] == ')') {
int ret{};
if (sym.empty()) {
ret = evaluate(expr, &nc);
} else {
ret = nc.GetValue(sym);
}
assert(!expr.empty() && expr[0] == ')');
expr.remove_prefix(1);
return ret;
}
assert(!expr.empty() && expr[0] == ' ');
expr.remove_prefix(1);
int value = evaluate(expr, &nc);
nc.AddValue(sym, value);
}
assert(0);
}
}
if (isdigit(expr[0]) || expr[0] == '-') {
auto pos = expr.find_first_not_of("-0123456789");
auto len = min(expr.length(), pos);
int num;
if (auto [ptr, ec] = from_chars(expr.data(), expr.data()+len, num); ec == errc()) {
expr.remove_prefix(len);
} else {
assert(0);
}
return num;
}
if (isalpha(expr[0])) {
string_view sym = symbol(expr);
assert(!expr.empty() && (expr[0] == ' ' || expr[0] == ')'));
return context->GetValue(sym);
}
assert(0);
return numeric_limits<int>::min();
}
public:
int evaluate(string expression) {
string_view expr(expression);
Context context(nullptr);
return evaluate(expr, &context);
}
};