Skip to content

Commit 0675b9b

Browse files
committed
添加calculator
1 parent e6e33a1 commit 0675b9b

File tree

2 files changed

+207
-0
lines changed

2 files changed

+207
-0
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,7 @@ target_link_libraries(tetris PRIVATE ncursesw)
5656
##### snake #####
5757
add_executable(snake snake.cpp Snake.h Snake.cpp Map.h Map.cpp vec2.h vec2.cpp)
5858
target_link_libraries(snake PRIVATE ncursesw)
59+
60+
##### calculator #####
61+
add_executable(calculator calculator.cpp)
62+
target_link_libraries(calculator)

calculator.cpp

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#include <iostream>
2+
#include <stack>
3+
4+
void TakeBlank(const std::string &expr, double &opera, size_t &pos) {
5+
for (; pos < expr.size(); ++pos) {
6+
if (std::isblank(expr[pos])) {
7+
continue;
8+
} else {
9+
return;
10+
}
11+
}
12+
}
13+
14+
bool TakeNumber(const std::string &expr, double &opera, size_t &pos) {
15+
size_t begin = pos;
16+
size_t len{};
17+
for (; pos < expr.size(); ++pos) {
18+
if (std::isdigit(expr[pos]) || expr[pos] == '.' || (len == 0 && expr[pos] == '-')) {
19+
++len;
20+
continue;
21+
} else {
22+
break;
23+
}
24+
}
25+
opera = std::stod(expr.substr(begin, len));
26+
return len;
27+
}
28+
29+
bool TakeOp(const std::string &expr, char &op, size_t &pos) {
30+
if (expr.size() <= pos) {
31+
return false;
32+
}
33+
switch (expr[pos]) {
34+
case '+':
35+
case '-':
36+
case '*':
37+
case '/':
38+
case '(':
39+
case ')':
40+
op = expr[pos];
41+
++pos;
42+
return true;
43+
default:
44+
return false;
45+
}
46+
}
47+
48+
bool TestOp(const std::string &expr, char op, size_t pos) {
49+
if (expr.size() <= pos) {
50+
return false;
51+
}
52+
return expr[pos] == op;
53+
}
54+
55+
int GetPri(char op) {
56+
switch (op) {
57+
case '+':
58+
case '-':
59+
return 1;
60+
case '*':
61+
case '/':
62+
return 2;
63+
default:
64+
std::cerr << "ERROR: invalid operator" << std::endl;
65+
std::exit(1);
66+
}
67+
}
68+
69+
void CalOnce(std::stack<double> &opera_stack, std::stack<char> &op_stack) {
70+
if (opera_stack.size() < 2) {
71+
std::cerr << "ERROR: invalid cal once" << std::endl;
72+
std::exit(1);
73+
}
74+
75+
if (op_stack.size() != opera_stack.size() - 1) {
76+
std::cerr << "ERROR: invalid op stack" << std::endl;
77+
std::exit(1);
78+
}
79+
80+
char op = op_stack.top();
81+
op_stack.pop();
82+
double opera[2]{};
83+
opera[1] = opera_stack.top();
84+
opera_stack.pop();
85+
opera[0] = opera_stack.top();
86+
opera_stack.pop();
87+
double tmp_res{};
88+
89+
switch (op) {
90+
case '+':
91+
tmp_res = opera[0] + opera[1];
92+
break;
93+
case '-':
94+
tmp_res = opera[0] - opera[1];
95+
break;
96+
case '*':
97+
tmp_res = opera[0] * opera[1];
98+
break;
99+
case '/':
100+
tmp_res = opera[0] / opera[1];
101+
break;
102+
default:
103+
std::cerr << "ERROR: invalid operator" << std::endl;
104+
std::exit(1);
105+
}
106+
opera_stack.push(tmp_res);
107+
}
108+
109+
void Cal(std::stack<double> &opera_stack, std::stack<char> &op_stack) {
110+
for (; 2 <= opera_stack.size();) {
111+
CalOnce(opera_stack, op_stack);
112+
}
113+
}
114+
115+
double ExecExpr(const std::string &expr, size_t &pos) {
116+
size_t pos_start = pos;
117+
std::stack<double> opera_stack;
118+
std::stack<char> op_stack;
119+
for (;;) {
120+
char op{};
121+
double opera{};
122+
123+
TakeBlank(expr, opera, pos);
124+
if (pos == expr.size()) {
125+
Cal(opera_stack, op_stack);
126+
if (opera_stack.size() == 1 && op_stack.empty()) {
127+
std::cout << "EXPR: " << expr << " RES: " << opera_stack.top() << std::endl;
128+
return opera_stack.top();
129+
} else {
130+
std::cout << "ERROR: invalid expr" << std::endl;
131+
std::exit(1);
132+
}
133+
}
134+
if (TestOp(expr, ')', pos)) {
135+
Cal(opera_stack, op_stack);
136+
if (opera_stack.size() == 1 && op_stack.empty()) {
137+
std::cout << "SUB EXPR: " << expr.substr(pos_start, pos - pos_start) << " RES: " << opera_stack.top() << std::endl;
138+
return opera_stack.top();
139+
} else {
140+
std::cout << "ERROR: invalid expr" << std::endl;
141+
std::exit(1);
142+
}
143+
}
144+
145+
if (opera_stack.size() == op_stack.size()) {
146+
if (TestOp(expr, '(', pos)) {
147+
// take (
148+
TakeOp(expr, op, pos);
149+
150+
// cal ()
151+
double tmp_result = ExecExpr(expr, pos);
152+
opera_stack.push(tmp_result);
153+
154+
// take )
155+
if (!TestOp(expr, ')', pos)) {
156+
std::cerr << "ERROR: no )" << std::endl;
157+
std::exit(1);
158+
}
159+
TakeOp(expr, op, pos);
160+
continue;
161+
}
162+
163+
if (TakeNumber(expr, opera, pos)) {
164+
opera_stack.push(opera);
165+
continue;
166+
} else {
167+
std::cerr << "ERROR: expect number" << std::endl;
168+
std::exit(1);
169+
}
170+
}
171+
172+
if (TakeOp(expr, op, pos)) {
173+
if (!op_stack.empty() && GetPri(op) <= GetPri(op_stack.top())) {
174+
CalOnce(opera_stack, op_stack);
175+
}
176+
op_stack.push(op);
177+
continue;
178+
} else {
179+
std::cerr << "ERROR: expect operator" << std::endl;
180+
std::exit(1);
181+
}
182+
}
183+
}
184+
185+
int main() {
186+
// handle line expr
187+
for (;;) {
188+
std::string expr;
189+
std::getline(std::cin, expr);
190+
191+
if (expr.empty()) {
192+
break;
193+
}
194+
if (expr[0] == '#') {
195+
continue;
196+
}
197+
198+
// exec expr
199+
size_t pos{};
200+
ExecExpr(expr, pos);
201+
}
202+
return 0;
203+
}

0 commit comments

Comments
 (0)