diff options
author | Li Jin <dragon-fly@qq.com> | 2017-07-13 16:03:11 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2017-07-13 16:03:11 +0800 |
commit | cb906e739f27931e9798510cd83725131ed55209 (patch) | |
tree | 52b465c5eb2250dec3ed3d5f02b86db79653b838 /MoonParser/ast.hpp | |
parent | 975c3c7dfa032229272c3b225de1127f1605e2d2 (diff) | |
download | yuescript-cb906e739f27931e9798510cd83725131ed55209.tar.gz yuescript-cb906e739f27931e9798510cd83725131ed55209.tar.bz2 yuescript-cb906e739f27931e9798510cd83725131ed55209.zip |
rewrite parsing codes with parserlib.
Diffstat (limited to 'MoonParser/ast.hpp')
-rw-r--r-- | MoonParser/ast.hpp | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/MoonParser/ast.hpp b/MoonParser/ast.hpp new file mode 100644 index 0000000..5d87db9 --- /dev/null +++ b/MoonParser/ast.hpp | |||
@@ -0,0 +1,437 @@ | |||
1 | #ifndef AST_HPP | ||
2 | #define AST_HPP | ||
3 | |||
4 | |||
5 | #include <cassert> | ||
6 | #include <list> | ||
7 | #include <stdexcept> | ||
8 | #include "parser.hpp" | ||
9 | |||
10 | |||
11 | namespace parserlib { | ||
12 | |||
13 | |||
14 | class ast_node; | ||
15 | template <class T, bool OPT> class ast_ptr; | ||
16 | template <class T> class ast_list; | ||
17 | template <class T> class ast; | ||
18 | |||
19 | |||
20 | /** type of AST node stack. | ||
21 | */ | ||
22 | typedef std::vector<ast_node *> ast_stack; | ||
23 | |||
24 | |||
25 | /** Base class for AST nodes. | ||
26 | */ | ||
27 | class ast_node : public input_range { | ||
28 | public: | ||
29 | ///constructor. | ||
30 | ast_node() : m_parent(0) {} | ||
31 | |||
32 | /** copy constructor. | ||
33 | @param n source object. | ||
34 | */ | ||
35 | ast_node(const ast_node &n) : m_parent(0) {} | ||
36 | |||
37 | ///destructor. | ||
38 | virtual ~ast_node() {} | ||
39 | |||
40 | /** assignment operator. | ||
41 | @param n source object. | ||
42 | @return reference to this. | ||
43 | */ | ||
44 | ast_node &operator = (const ast_node &n) { return *this; } | ||
45 | |||
46 | /** get the parent node. | ||
47 | @return the parent node, if there is one. | ||
48 | */ | ||
49 | ast_node *parent() const { return m_parent; } | ||
50 | |||
51 | /** interface for filling the contents of the node | ||
52 | from a node stack. | ||
53 | @param st stack. | ||
54 | */ | ||
55 | virtual void construct(ast_stack &st) {} | ||
56 | |||
57 | private: | ||
58 | //parent | ||
59 | ast_node *m_parent; | ||
60 | |||
61 | template <class T, bool OPT> friend class ast_ptr; | ||
62 | template <class T> friend class ast_list; | ||
63 | template <class T> friend class ast; | ||
64 | }; | ||
65 | |||
66 | |||
67 | class ast_member; | ||
68 | |||
69 | |||
70 | /** type of ast member vector. | ||
71 | */ | ||
72 | typedef std::vector<ast_member *> ast_member_vector; | ||
73 | |||
74 | |||
75 | /** base class for AST nodes with children. | ||
76 | */ | ||
77 | class ast_container : public ast_node { | ||
78 | public: | ||
79 | /** sets the container under construction to be this. | ||
80 | */ | ||
81 | ast_container(); | ||
82 | |||
83 | /** sets the container under construction to be this. | ||
84 | Members are not copied. | ||
85 | @param src source object. | ||
86 | */ | ||
87 | ast_container(const ast_container &src); | ||
88 | |||
89 | /** the assignment operator. | ||
90 | The members are not copied. | ||
91 | @param src source object. | ||
92 | @return reference to this. | ||
93 | */ | ||
94 | ast_container &operator = (const ast_container &src) { | ||
95 | return *this; | ||
96 | } | ||
97 | |||
98 | /** returns the vector of AST members. | ||
99 | @return the vector of AST members. | ||
100 | */ | ||
101 | const ast_member_vector &members() const { | ||
102 | return m_members; | ||
103 | } | ||
104 | |||
105 | /** Asks all members to construct themselves from the stack. | ||
106 | The members are asked to construct themselves in reverse order. | ||
107 | from a node stack. | ||
108 | @param st stack. | ||
109 | */ | ||
110 | virtual void construct(ast_stack &st); | ||
111 | |||
112 | private: | ||
113 | ast_member_vector m_members; | ||
114 | |||
115 | friend class ast_member; | ||
116 | }; | ||
117 | |||
118 | |||
119 | /** Base class for children of ast_container. | ||
120 | */ | ||
121 | class ast_member { | ||
122 | public: | ||
123 | /** automatically registers itself to the container under construction. | ||
124 | */ | ||
125 | ast_member() { _init(); } | ||
126 | |||
127 | /** automatically registers itself to the container under construction. | ||
128 | @param src source object. | ||
129 | */ | ||
130 | ast_member(const ast_member &src) { _init(); } | ||
131 | |||
132 | /** the assignment operator. | ||
133 | @param src source object. | ||
134 | @return reference to this. | ||
135 | */ | ||
136 | ast_member &operator = (const ast_member &src) { | ||
137 | return *this; | ||
138 | } | ||
139 | |||
140 | /** returns the container this belongs to. | ||
141 | @return the container this belongs to. | ||
142 | */ | ||
143 | ast_container *container() const { return m_container; } | ||
144 | |||
145 | /** interface for filling the the member from a node stack. | ||
146 | @param st stack. | ||
147 | */ | ||
148 | virtual void construct(ast_stack &st) = 0; | ||
149 | |||
150 | private: | ||
151 | //the container this belongs to. | ||
152 | ast_container *m_container; | ||
153 | |||
154 | //register the AST member to the current container. | ||
155 | void _init(); | ||
156 | }; | ||
157 | |||
158 | |||
159 | /** pointer to an AST object. | ||
160 | It assumes ownership of the object. | ||
161 | It pops an object of the given type from the stack. | ||
162 | @tparam T type of object to control. | ||
163 | @tparam OPT if true, the object becomes optional. | ||
164 | */ | ||
165 | template <class T, bool OPT = false> class ast_ptr : public ast_member { | ||
166 | public: | ||
167 | /** the default constructor. | ||
168 | @param obj object. | ||
169 | */ | ||
170 | ast_ptr(T *obj = 0) : m_ptr(obj) { | ||
171 | _set_parent(); | ||
172 | } | ||
173 | |||
174 | /** the copy constructor. | ||
175 | It duplicates the underlying object. | ||
176 | @param src source object. | ||
177 | */ | ||
178 | ast_ptr(const ast_ptr<T, OPT> &src) : | ||
179 | m_ptr(src.m_ptr ? new T(*src.m_ptr) : 0) | ||
180 | { | ||
181 | _set_parent(); | ||
182 | } | ||
183 | |||
184 | /** deletes the underlying object. | ||
185 | */ | ||
186 | ~ast_ptr() { | ||
187 | delete m_ptr; | ||
188 | } | ||
189 | |||
190 | /** copies the given object. | ||
191 | The old object is deleted. | ||
192 | @param obj new object. | ||
193 | @return reference to this. | ||
194 | */ | ||
195 | ast_ptr<T, OPT> &operator = (const T *obj) { | ||
196 | delete m_ptr; | ||
197 | m_ptr = obj ? new T(*obj) : 0; | ||
198 | _set_parent(); | ||
199 | return *this; | ||
200 | } | ||
201 | |||
202 | /** copies the underlying object. | ||
203 | The old object is deleted. | ||
204 | @param src source object. | ||
205 | @return reference to this. | ||
206 | */ | ||
207 | ast_ptr<T, OPT> &operator = (const ast_ptr<T, OPT> &src) { | ||
208 | delete m_ptr; | ||
209 | m_ptr = src.m_ptr ? new T(*src.m_ptr) : 0; | ||
210 | _set_parent(); | ||
211 | return *this; | ||
212 | } | ||
213 | |||
214 | /** gets the underlying ptr value. | ||
215 | @return the underlying ptr value. | ||
216 | */ | ||
217 | T *get() const { | ||
218 | return m_ptr; | ||
219 | } | ||
220 | |||
221 | /** auto conversion to the underlying object ptr. | ||
222 | @return the underlying ptr value. | ||
223 | */ | ||
224 | operator T *() const { | ||
225 | return m_ptr; | ||
226 | } | ||
227 | |||
228 | /** member access. | ||
229 | @return the underlying ptr value. | ||
230 | */ | ||
231 | T *operator ->() const { | ||
232 | assert(m_ptr); | ||
233 | return m_ptr; | ||
234 | } | ||
235 | |||
236 | /** Pops a node from the stack. | ||
237 | @param st stack. | ||
238 | @exception std::logic_error thrown if the node is not of the appropriate type; | ||
239 | thrown only if OPT == false or if the stack is empty. | ||
240 | */ | ||
241 | virtual void construct(ast_stack &st) { | ||
242 | //check the stack node | ||
243 | if (st.empty()) throw std::logic_error("invalid AST stack"); | ||
244 | |||
245 | //get the node | ||
246 | ast_node *node = st.back(); | ||
247 | |||
248 | //get the object | ||
249 | T *obj = dynamic_cast<T *>(node); | ||
250 | |||
251 | //if the object is optional, simply return | ||
252 | if (OPT) { | ||
253 | if (!obj) return; | ||
254 | } | ||
255 | |||
256 | //else if the object is mandatory, throw an exception | ||
257 | else { | ||
258 | if (!obj) throw std::logic_error("invalid AST node"); | ||
259 | } | ||
260 | |||
261 | //pop the node from the stack | ||
262 | st.pop_back(); | ||
263 | |||
264 | //set the new object | ||
265 | delete m_ptr; | ||
266 | m_ptr = obj; | ||
267 | _set_parent(); | ||
268 | } | ||
269 | |||
270 | private: | ||
271 | //ptr | ||
272 | T *m_ptr; | ||
273 | |||
274 | //set parent of object | ||
275 | void _set_parent() { | ||
276 | if (m_ptr) m_ptr->m_parent = container(); | ||
277 | } | ||
278 | }; | ||
279 | |||
280 | |||
281 | /** A list of objects. | ||
282 | It pops objects of the given type from the ast stack, until no more objects can be popped. | ||
283 | It assumes ownership of objects. | ||
284 | @tparam T type of object to control. | ||
285 | */ | ||
286 | template <class T> class ast_list : public ast_member { | ||
287 | public: | ||
288 | ///list type. | ||
289 | typedef std::list<T *> container; | ||
290 | |||
291 | ///the default constructor. | ||
292 | ast_list() {} | ||
293 | |||
294 | /** duplicates the objects of the given list. | ||
295 | @param src source object. | ||
296 | */ | ||
297 | ast_list(const ast_list<T> &src) { | ||
298 | _dup(src); | ||
299 | } | ||
300 | |||
301 | /** deletes the objects. | ||
302 | */ | ||
303 | ~ast_list() { | ||
304 | _clear(); | ||
305 | } | ||
306 | |||
307 | /** deletes the objects of this list and duplicates the given one. | ||
308 | @param src source object. | ||
309 | @return reference to this. | ||
310 | */ | ||
311 | ast_list<T> &operator = (const ast_list<T> &src) { | ||
312 | if (&src != this) { | ||
313 | _clear(); | ||
314 | _dup(src); | ||
315 | } | ||
316 | return *this; | ||
317 | } | ||
318 | |||
319 | /** returns the container of objects. | ||
320 | @return the container of objects. | ||
321 | */ | ||
322 | const container &objects() const { | ||
323 | return m_objects; | ||
324 | } | ||
325 | |||
326 | /** Pops objects of type T from the stack until no more objects can be popped. | ||
327 | @param st stack. | ||
328 | */ | ||
329 | virtual void construct(ast_stack &st) { | ||
330 | for(;;) { | ||
331 | //if the stack is empty | ||
332 | if (st.empty()) break; | ||
333 | |||
334 | //get the node | ||
335 | ast_node *node = st.back(); | ||
336 | |||
337 | //get the object | ||
338 | T *obj = dynamic_cast<T *>(node); | ||
339 | |||
340 | //if the object was not not of the appropriate type, | ||
341 | //end the list parsing | ||
342 | if (!obj) return; | ||
343 | |||
344 | //remove the node from the stack | ||
345 | st.pop_back(); | ||
346 | |||
347 | //insert the object in the list, in reverse order | ||
348 | m_objects.push_front(obj); | ||
349 | |||
350 | //set the object's parent | ||
351 | obj->m_parent = ast_member::container(); | ||
352 | } | ||
353 | } | ||
354 | |||
355 | private: | ||
356 | //objects | ||
357 | container m_objects; | ||
358 | |||
359 | //deletes the objects of this list. | ||
360 | void _clear() { | ||
361 | while (!m_objects.empty()) { | ||
362 | delete m_objects.back(); | ||
363 | m_objects.pop_back(); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | //duplicate the given list. | ||
368 | void _dup(const ast_list<T> &src) { | ||
369 | for(typename container::const_iterator it = src.m_objects.begin(); | ||
370 | it != src.m_objects.end(); | ||
371 | ++it) | ||
372 | { | ||
373 | T *obj = new T(*it); | ||
374 | m_objects.push_back(obj); | ||
375 | obj->m_parent = ast_member::container(); | ||
376 | } | ||
377 | } | ||
378 | }; | ||
379 | |||
380 | |||
381 | /** AST function which creates an object of type T | ||
382 | and pushes it to the node stack. | ||
383 | */ | ||
384 | template <class T> class ast { | ||
385 | public: | ||
386 | /** constructor. | ||
387 | @param r rule to attach the AST function to. | ||
388 | */ | ||
389 | ast(rule &r) { | ||
390 | r.set_parse_proc(&_parse_proc); | ||
391 | } | ||
392 | |||
393 | private: | ||
394 | //parse proc | ||
395 | static void _parse_proc(const pos &b, const pos &e, void *d) { | ||
396 | ast_stack *st = reinterpret_cast<ast_stack *>(d); | ||
397 | T *obj = new T; | ||
398 | obj->m_begin = b; | ||
399 | obj->m_end = e; | ||
400 | obj->construct(*st); | ||
401 | st->push_back(obj); | ||
402 | } | ||
403 | }; | ||
404 | |||
405 | |||
406 | /** parses the given input. | ||
407 | @param i input. | ||
408 | @param g root rule of grammar. | ||
409 | @param el list of errors. | ||
410 | @param ud user data, passed to the parse procedures. | ||
411 | @return pointer to ast node created, or null if there was an error. | ||
412 | The return object must be deleted by the caller. | ||
413 | */ | ||
414 | ast_node *parse(input &i, rule &g, error_list &el, void* ud); | ||
415 | |||
416 | |||
417 | /** parses the given input. | ||
418 | @param i input. | ||
419 | @param g root rule of grammar. | ||
420 | @param el list of errors. | ||
421 | @param ast result pointer to created ast. | ||
422 | @param ud user data, passed to the parse procedures. | ||
423 | @return true on success, false on error. | ||
424 | */ | ||
425 | template <class T> bool parse(input &i, rule &g, error_list &el, T *&ast, void* ud = nullptr) { | ||
426 | ast_node *node = parse(i, g, el, ud); | ||
427 | ast = dynamic_cast<T *>(node); | ||
428 | if (ast) return true; | ||
429 | delete node; | ||
430 | return false; | ||
431 | } | ||
432 | |||
433 | |||
434 | } //namespace parserlib | ||
435 | |||
436 | |||
437 | #endif //AST_HPP | ||