-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrpn-calc-printer.cpp
113 lines (100 loc) · 2.36 KB
/
rpn-calc-printer.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
// rpn-calc-printer.cpp : convert an infix expression to reverse polish notation
// note: from bash, run with eg. '$ echo "2+3*9-1" | ./rpn-calc-printer'
#include <iostream>
#include <cctype>
using std::cout;
using std::cerr;
using std::cin;
using std::istream;
using std::ostream;
using Number = double;
enum class Op : char {
add = '+',
subtract = '-',
multiply = '*',
divide = '/',
number = '.',
none = '\0'
};
class StackMachine {
public:
virtual ~StackMachine() = default;
virtual void apply_operator(Op op) = 0;
virtual void push_number(Number n) = 0;
};
class StackPrinter final : public StackMachine {
ostream& out;
public:
StackPrinter(ostream& os = cout) : out{os} {}
virtual ~StackPrinter() {
out << '\n';
}
virtual void apply_operator(Op op) override {
out << ' ' << static_cast<char>(op);
}
virtual void push_number(Number n) override {
out << ' ' << n;
}
};
struct Symbol {
Op sym;
Number num;
};
class ExpressionEvaluator {
Symbol lookahead;
istream& in;
StackMachine& target;
void next();
void term();
void factor();
public:
ExpressionEvaluator(StackMachine& sm, istream& is = cin)
: target{sm}, in{is} { next(); }
void expression();
};
int main() {
StackPrinter sp;
ExpressionEvaluator eval(sp);
eval.expression();
}
void ExpressionEvaluator::next() {
char c{};
in >> c;
if (isdigit(c) || (c == '.')) {
in.unget();
in >> lookahead.num;
lookahead.sym = Op::number;
}
else {
lookahead.num = Number{};
lookahead.sym = static_cast<Op>(c);
}
}
void ExpressionEvaluator::expression() {
term();
while ((lookahead.sym == Op::add) || (lookahead.sym == Op::subtract)) {
Op op{ lookahead.sym };
next();
term();
target.apply_operator(op);
}
}
void ExpressionEvaluator::term() {
factor();
while ((lookahead.sym == Op::multiply) || (lookahead.sym == Op::divide)) {
Op op{ lookahead.sym };
next();
factor();
target.apply_operator(op);
}
}
void ExpressionEvaluator::factor() {
if (lookahead.sym == Op::number) {
target.push_number(lookahead.num);
next();
}
else {
cerr << "Unknown operator: "
<< static_cast<char>(lookahead.sym) << '\n';
}
}