-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsimple_calc.cpp
More file actions
183 lines (172 loc) · 5.58 KB
/
Copy pathsimple_calc.cpp
File metadata and controls
183 lines (172 loc) · 5.58 KB
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <stdexcept>
static int s_levels = 0;
class Level {
double m_val;
char m_op;
int m_prior;
const char get_oper() {
return m_op;
}
public:
Level* prev;
Level* next;
Level(const double in_val, const char in_op, const int in_prior, Level* in_prev) {
m_val = in_val;
m_op = in_op;
m_prior = in_prior;
prev = in_prev;
next = nullptr;
++s_levels;
std::cout << "create level #" << s_levels << ": val: " << m_val << "; oper: " << m_op << "; prior: " << m_prior << std::endl;
}
~Level() = default;
const double GetValue() {
return m_val;
}
const int GetPriority() {
return m_prior;
}
void exec() {
if (next) {
double rv = next->GetValue();
switch (m_op) {
case '+':
m_val += rv;
break;
case '-':
m_val -= rv;
break;
case '*':
m_val *= rv;
break;
case '/':
m_val /= rv;
break;
default: break;
}
m_op = next->get_oper();
m_prior = next->GetPriority();
std::cout << " Exec: val: " << m_val << "; oper: " << m_op << "; prior: " << m_prior << std::endl;
delete next;
--s_levels;
next = nullptr;
}
}
};
enum eCharType {
eDIGIT,
ePOINT,
eOPER,
eLB,
eRB,
eUNDEF
};
static const std::map<char, uint8_t> sc_priorities {{
{'+', 0},
{'-', 0},
{'*', 1},
{'/', 1}
}};
static const int sc_bracket_weight = 3;
const double process(const std::string& line) {
std::string value = "";
char oper = 0;
long long prior = -1;
long long bprior = 0;
eCharType last = eUNDEF;
Level* curr = nullptr;
auto chit = std::begin(line);
do {
const char ch = *chit;
if (std::isdigit(ch)) {
if (last != eRB) {
value.push_back(ch);
last = eDIGIT;
} else {
std::cout << "Digit '" << ch << "' on pos " << chit - std::begin(line) << std::endl;
throw std::domain_error("unexpected digit");
}
} else if (ch == '.') {
if (last == eDIGIT) {
value.push_back(ch);
last = ePOINT;
} else {
std::cout << "Point symbol '" << ch << "' on pos " << chit - std::begin(line) << std::endl;
throw std::domain_error("unexpected point symbol");
}
} else if (sc_priorities.count(ch)) {
if (last == eDIGIT || last == eRB) {
oper = ch;
prior = bprior + sc_priorities.at(ch);
last = eOPER;
} else {
std::cout << "Operator '" << ch << "' on pos " << chit - std::begin(line) << std::endl;
throw std::domain_error("unexpected operator");
}
} else if (ch == '(') {
if (last != eDIGIT && last != ePOINT && last != eRB) {
bprior += sc_bracket_weight;
last = eLB;
} else {
std::cout << "Bracket symbol '" << ch << "' on pos " << chit - std::begin(line) << std::endl;
throw std::domain_error("unexpected left bracket");
}
} else if (ch == ')') {
if ((last == eDIGIT || last == eRB) && bprior - sc_bracket_weight >= 0) {
bprior -= sc_bracket_weight;
last = eRB;
} else {
std::cout << "Bracket symbol '" << ch << "' on pos " << chit - std::begin(line) << std::endl;
throw std::domain_error("unexpected right bracket");
}
} else if (std::isspace(ch)) {
} else {
std::cout << "Unknown symbol '" << ch << "' on pos " << chit - std::begin(line) << std::endl;
throw std::domain_error("unexpected symbol");
}
++chit;
if (!value.empty() && (oper || chit == std::end(line))) {
Level* lev = new Level(std::stod(value), oper, prior, curr);
if (curr) {
curr->next = lev;
curr = curr->next;
} else curr = lev;
while (curr->prev && (
curr->prev->GetPriority() > curr->GetPriority() ||
curr->prev->GetPriority() == curr->GetPriority())) {
curr = curr->prev;
curr->exec();
}
value.clear();
oper = 0;
prior = -1;
}
} while (chit != std::end(line));
if (!curr) throw std::domain_error("invalid expression");
return curr->GetValue();
}
int main() {
std::string line;
while (!std::cin.eof()) {
std::getline(std::cin, line);
if (!line.compare("exit") ||
!line.compare("quit") ||
!line.compare("q") ||
!line.compare("e")) {
break;
} else if (line.length() > 0) {
try {
std::cout << process(line) << std::endl;
} catch (std::exception &e) {
std::cout << "error: " << e.what() << std::endl;
}
}
}
return 0;
}