Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / atf / dist / atf-c++ / parser.hpp
blobec9431c94c16743f75dca042753169b94a00673b
1 //
2 // Automated Testing Framework (atf)
3 //
4 // Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 // 1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // 2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #if !defined(_ATF_CXX_PARSER_HPP_)
31 #define _ATF_CXX_PARSER_HPP_
33 #include <map>
34 #include <stdexcept>
35 #include <string>
36 #include <utility>
37 #include <vector>
39 namespace atf {
40 namespace parser {
42 // ------------------------------------------------------------------------
43 // The "parse_error" class.
44 // ------------------------------------------------------------------------
46 class parse_error : public std::runtime_error,
47 public std::pair< size_t, std::string > {
48 mutable std::string m_msg;
50 public:
51 parse_error(size_t, std::string);
52 ~parse_error(void) throw();
54 const char* what(void) const throw();
57 // ------------------------------------------------------------------------
58 // The "parse_errors" class.
59 // ------------------------------------------------------------------------
61 class parse_errors : public std::runtime_error,
62 public std::vector< parse_error > {
63 std::vector< parse_error > m_errors;
64 mutable std::string m_msg;
66 public:
67 parse_errors(void);
68 ~parse_errors(void) throw();
70 const char* what(void) const throw();
73 // ------------------------------------------------------------------------
74 // The "token" class.
75 // ------------------------------------------------------------------------
77 typedef int token_type;
79 //!
80 //! \brief Representation of a read token.
81 //!
82 //! A pair that contains the information of a token read from a stream.
83 //! It contains the token's type and its associated data, if any.
84 //!
85 struct token {
86 bool m_inited;
87 size_t m_line;
88 token_type m_type;
89 std::string m_text;
91 public:
92 token(void);
93 token(size_t, const token_type&, const std::string& = "");
95 size_t lineno(void) const;
96 const token_type& type(void) const;
97 const std::string& text(void) const;
99 operator bool(void) const;
100 bool operator!(void) const;
103 // ------------------------------------------------------------------------
104 // The "tokenizer" class.
105 // ------------------------------------------------------------------------
108 //! \brief A stream tokenizer.
110 //! This template implements an extremely simple, line-oriented stream
111 //! tokenizer. It is only able to recognize one character-long delimiters,
112 //! random-length keywords, skip whitespace and, anything that does not
113 //! match these rules is supposed to be a word.
115 //! Parameter IS: The input stream's type.
117 template< class IS >
118 class tokenizer {
119 IS& m_is;
120 size_t m_lineno;
121 token m_la;
123 bool m_skipws;
124 token_type m_eof_type, m_nl_type, m_text_type;
126 std::map< char, token_type > m_delims_map;
127 std::string m_delims_str;
129 char m_quotech;
130 token_type m_quotetype;
132 std::map< std::string, token_type > m_keywords_map;
134 token_type alloc_type(void);
136 template< class TKZ >
137 friend
138 class parser;
140 public:
141 tokenizer(IS&, bool, const token_type&, const token_type&,
142 const token_type&, size_t = 1);
144 size_t lineno(void) const;
146 void add_delim(char, const token_type&);
147 void add_keyword(const std::string&, const token_type&);
148 void add_quote(char, const token_type&);
150 token next(void);
151 std::string rest_of_line(void);
154 template< class IS >
155 tokenizer< IS >::tokenizer(IS& p_is,
156 bool p_skipws,
157 const token_type& p_eof_type,
158 const token_type& p_nl_type,
159 const token_type& p_text_type,
160 size_t p_lineno) :
161 m_is(p_is),
162 m_lineno(p_lineno),
163 m_skipws(p_skipws),
164 m_eof_type(p_eof_type),
165 m_nl_type(p_nl_type),
166 m_text_type(p_text_type),
167 m_quotech(-1)
171 template< class IS >
172 size_t
173 tokenizer< IS >::lineno(void)
174 const
176 return m_lineno;
179 template< class IS >
180 void
181 tokenizer< IS >::add_delim(char delim, const token_type& type)
183 m_delims_map[delim] = type;
184 m_delims_str += delim;
187 template< class IS >
188 void
189 tokenizer< IS >::add_keyword(const std::string& keyword,
190 const token_type& type)
192 m_keywords_map[keyword] = type;
195 template< class IS >
196 void
197 tokenizer< IS >::add_quote(char ch, const token_type& type)
199 m_quotech = ch;
200 m_quotetype = type;
203 template< class IS >
204 token
205 tokenizer< IS >::next(void)
207 if (m_la) {
208 token t = m_la;
209 m_la = token();
210 if (t.type() == m_nl_type)
211 m_lineno++;
212 return t;
215 char ch;
216 std::string text;
218 bool done = false, quoted = false;
219 token t(m_lineno, m_eof_type, "<<EOF>>");
220 while (!done && m_is.get(ch).good()) {
221 if (ch == m_quotech) {
222 if (text.empty()) {
223 bool escaped = false;
224 while (!done && m_is.get(ch).good()) {
225 if (!escaped) {
226 if (ch == '\\')
227 escaped = true;
228 else if (ch == '\n') {
229 m_la = token(m_lineno, m_nl_type, "<<NEWLINE>>");
230 throw parse_error(t.lineno(),
231 "Missing double quotes before "
232 "end of line");
233 } else if (ch == m_quotech)
234 done = true;
235 else
236 text += ch;
237 } else {
238 text += ch;
239 escaped = false;
242 if (!m_is.good())
243 throw parse_error(t.lineno(),
244 "Missing double quotes before "
245 "end of file");
246 t = token(m_lineno, m_text_type, text);
247 quoted = true;
248 } else {
249 m_is.unget();
250 done = true;
252 } else {
253 typename std::map< char, token_type >::const_iterator idelim;
254 idelim = m_delims_map.find(ch);
255 if (idelim != m_delims_map.end()) {
256 done = true;
257 if (text.empty())
258 t = token(m_lineno, (*idelim).second,
259 std::string("") + ch);
260 else
261 m_is.unget();
262 } else if (ch == '\n') {
263 done = true;
264 if (text.empty())
265 t = token(m_lineno, m_nl_type, "<<NEWLINE>>");
266 else
267 m_is.unget();
268 } else if (m_skipws && (ch == ' ' || ch == '\t')) {
269 if (!text.empty())
270 done = true;
271 } else
272 text += ch;
276 if (!quoted && !text.empty()) {
277 typename std::map< std::string, token_type >::const_iterator ikw;
278 ikw = m_keywords_map.find(text);
279 if (ikw != m_keywords_map.end())
280 t = token(m_lineno, (*ikw).second, text);
281 else
282 t = token(m_lineno, m_text_type, text);
285 if (t.type() == m_nl_type)
286 m_lineno++;
288 return t;
291 template< class IS >
292 std::string
293 tokenizer< IS >::rest_of_line(void)
295 std::string str;
296 while (m_is.good() && m_is.peek() != '\n')
297 str += m_is.get();
298 return str;
301 // ------------------------------------------------------------------------
302 // The "parser" class.
303 // ------------------------------------------------------------------------
305 template< class TKZ >
306 class parser {
307 TKZ& m_tkz;
308 token m_last;
309 parse_errors m_errors;
310 bool m_thrown;
312 public:
313 parser(TKZ& tkz);
314 ~parser(void);
316 bool good(void) const;
317 void add_error(const parse_error&);
318 bool has_errors(void) const;
320 token next(void);
321 std::string rest_of_line(void);
322 token reset(const token_type&);
324 token
325 expect(const token_type&,
326 const std::string&);
328 token
329 expect(const token_type&,
330 const token_type&,
331 const std::string&);
333 token
334 expect(const token_type&,
335 const token_type&,
336 const token_type&,
337 const std::string&);
339 token
340 expect(const token_type&,
341 const token_type&,
342 const token_type&,
343 const token_type&,
344 const std::string&);
346 token
347 expect(const token_type&,
348 const token_type&,
349 const token_type&,
350 const token_type&,
351 const token_type&,
352 const token_type&,
353 const token_type&,
354 const std::string&);
357 template< class TKZ >
358 parser< TKZ >::parser(TKZ& tkz) :
359 m_tkz(tkz),
360 m_thrown(false)
364 template< class TKZ >
365 parser< TKZ >::~parser(void)
367 if (!m_errors.empty() && !m_thrown)
368 throw m_errors;
371 template< class TKZ >
372 bool
373 parser< TKZ >::good(void)
374 const
376 return m_tkz.m_is.good();
379 template< class TKZ >
380 void
381 parser< TKZ >::add_error(const parse_error& pe)
383 m_errors.push_back(pe);
386 template< class TKZ >
387 bool
388 parser< TKZ >::has_errors(void)
389 const
391 return !m_errors.empty();
394 template< class TKZ >
395 token
396 parser< TKZ >::next(void)
398 token t = m_tkz.next();
400 m_last = t;
402 if (t.type() == m_tkz.m_eof_type) {
403 if (!m_errors.empty()) {
404 m_thrown = true;
405 throw m_errors;
409 return t;
412 template< class TKZ >
413 std::string
414 parser< TKZ >::rest_of_line(void)
416 return m_tkz.rest_of_line();
419 template< class TKZ >
420 token
421 parser< TKZ >::reset(const token_type& stop)
423 token t = m_last;
425 while (t.type() != m_tkz.m_eof_type && t.type() != stop)
426 t = next();
428 return t;
431 template< class TKZ >
432 token
433 parser< TKZ >::expect(const token_type& t1,
434 const std::string& textual)
436 token t = next();
438 if (t.type() != t1)
439 throw parse_error(t.lineno(),
440 "Unexpected token `" + t.text() +
441 "'; expected " + textual);
443 return t;
446 template< class TKZ >
447 token
448 parser< TKZ >::expect(const token_type& t1,
449 const token_type& t2,
450 const std::string& textual)
452 token t = next();
454 if (t.type() != t1 && t.type() != t2)
455 throw parse_error(t.lineno(),
456 "Unexpected token `" + t.text() +
457 "'; expected " + textual);
459 return t;
462 template< class TKZ >
463 token
464 parser< TKZ >::expect(const token_type& t1,
465 const token_type& t2,
466 const token_type& t3,
467 const std::string& textual)
469 token t = next();
471 if (t.type() != t1 && t.type() != t2 && t.type() != t3)
472 throw parse_error(t.lineno(),
473 "Unexpected token `" + t.text() +
474 "'; expected " + textual);
476 return t;
479 template< class TKZ >
480 token
481 parser< TKZ >::expect(const token_type& t1,
482 const token_type& t2,
483 const token_type& t3,
484 const token_type& t4,
485 const std::string& textual)
487 token t = next();
489 if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
490 t.type() != t4)
491 throw parse_error(t.lineno(),
492 "Unexpected token `" + t.text() +
493 "'; expected " + textual);
495 return t;
498 template< class TKZ >
499 token
500 parser< TKZ >::expect(const token_type& t1,
501 const token_type& t2,
502 const token_type& t3,
503 const token_type& t4,
504 const token_type& t5,
505 const token_type& t6,
506 const token_type& t7,
507 const std::string& textual)
509 token t = next();
511 if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
512 t.type() != t4 && t.type() != t5 && t.type() != t6 &&
513 t.type() != t7)
514 throw parse_error(t.lineno(),
515 "Unexpected token `" + t.text() +
516 "'; expected " + textual);
518 return t;
521 } // namespace parser
522 } // namespace atf
524 #endif // !defined(_ATF_CXX_PARSER_HPP_)