-
Notifications
You must be signed in to change notification settings - Fork 9
/
parser_simple.hpp
213 lines (178 loc) · 4.86 KB
/
parser_simple.hpp
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//----------------------------------------------------------------------------
// copyright 2012, 2013, 2014 Keean Schupke
// compile with -std=gnu++11
// parser_simple.hpp
#ifndef PARSER_SIMPLE_HPP
#define PARSER_SIMPLE_HPP
#include <istream>
#include <stdexcept>
using namespace std;
//----------------------------------------------------------------------------
// Character Predicates
struct char_pred {
string const name;
char_pred(string const n) : name(n) {}
virtual bool operator() (int const c) const = 0;
};
struct is_space : public char_pred {
is_space() : char_pred("space") {}
virtual bool operator() (int const c) const override {
return ::isspace(c) != 0;
}
} is_space;
struct is_digit : public char_pred {
is_digit() : char_pred("digit") {}
virtual bool operator() (int const c) const override {
return ::isdigit(c) != 0;
}
} is_digit;
struct is_upper : public char_pred {
is_upper() : char_pred("uppercase") {}
virtual bool operator() (int const c) const override {
return ::isupper(c) != 0;
}
} is_upper;
struct is_lower : public char_pred {
is_lower() : char_pred("lowercase") {}
virtual bool operator() (int const c) const override {
return ::islower(c) != 0;
}
} is_lower;
struct is_alpha : public char_pred {
is_alpha() : char_pred("alphabetic") {}
virtual bool operator() (int const c) const override {
return ::isalpha(c) != 0;
}
} is_alpha;
struct is_alnum : public char_pred {
is_alnum() : char_pred("alphanumeric") {}
virtual bool operator() (int const c) const override {
return ::isalnum(c) != 0;
}
} is_alnum;
struct is_print : public char_pred {
is_print() : char_pred("printable") {}
virtual bool operator() (int const c) const override {
return ::isprint(c) != 0;
}
} is_print;
class is_char : public char_pred {
int const k;
public:
explicit is_char(char const c)
: k(c), char_pred("'" + string(1, c) + "'") {}
virtual bool operator() (int const c) const override {
return k == c;
}
};
class is_either : public char_pred {
char_pred const &a;
char_pred const &b;
public:
is_either(char_pred const &a, char_pred const& b)
: a(a), b(b), char_pred("(" + a.name + " or " + b.name + ")") {}
bool operator() (int const c) const {
return a(c) || b(c);
}
};
class is_not : public char_pred {
char_pred const &a;
public:
explicit is_not(char_pred const &a)
: a(a), char_pred("~" + a.name) {}
bool operator() (int const c) const {
return !a(c);
}
};
is_char const is_minus('-');
//----------------------------------------------------------------------------
// Recursive Descent Parser
struct parse_error : public runtime_error {
int const row;
int const col;
int const sym;
string const exp;
parse_error(string const& what, int row, int col, string exp, int sym)
: runtime_error(what), row(row), col(col), exp(move(exp)), sym(sym) {}
};
class parser {
streambuf *in;
int count;
int row;
int col;
int sym;
void error(string const& err, string const exp) {
throw parse_error(err, row, col, exp, sym);
}
void next() {
sym = in->sgetc();
in->snextc();
++count;
if (sym == '\n') {
++row;
col = 1;
} else if (::isprint(sym)) {
++col;
}
}
public:
parser(istream &f) : in(f.rdbuf()), count(0), row(1), col(1), sym(in->sbumpc()) {}
protected:
int get_col() {
return col;
}
int get_row() {
return row;
}
int get_count() {
return count;
}
bool accept(char_pred const &t, string *s = nullptr) {
if (!t(sym)) {
return false;
}
if (s != nullptr) {
s->push_back(sym);
}
next();
return true;
}
bool expect(char_pred const &t, string *s = nullptr) {
if (!t(sym)) {
error("expected", t.name);
}
if (s != nullptr) {
s->push_back(sym);
}
next();
return true;
}
bool space(string *s = nullptr) {
if (accept(is_space)) {
if (s != nullptr) {
s->push_back(' ');
}
while (accept(is_space));
return true;
}
return false;
}
bool number(string *s = nullptr) {
if (accept(is_digit, s)) {
while (accept(is_digit, s));
return true;
}
return false;
}
bool signed_number(string *s = nullptr) {
return accept(is_minus, s), number(s);
}
bool name(string *s = nullptr) {
if (accept(is_alpha, s)) {
while (accept(is_alnum, s));
return true;
}
return false;
}
};
#endif // PARSER_SIMPLE_HPP