tools/llvm: Do not build with symbols
[minix3.git] / external / bsd / atf / dist / atf-c++ / detail / parser.hpp
blobf55973f50c42e4fbdce4287576e42ec88343b1f9
1 //
2 // Automated Testing Framework (atf)
3 //
4 // Copyright (c) 2007 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 <istream>
34 #include <map>
35 #include <ostream>
36 #include <stdexcept>
37 #include <string>
38 #include <utility>
39 #include <vector>
41 namespace atf {
42 namespace parser {
44 // ------------------------------------------------------------------------
45 // The "parse_error" class.
46 // ------------------------------------------------------------------------
48 class parse_error : public std::runtime_error,
49 public std::pair< size_t, std::string > {
50 mutable std::string m_msg;
52 public:
53 parse_error(size_t, std::string);
54 ~parse_error(void) throw();
56 const char* what(void) const throw();
58 operator std::string(void) const;
61 // ------------------------------------------------------------------------
62 // The "parse_errors" class.
63 // ------------------------------------------------------------------------
65 class parse_errors : public std::runtime_error,
66 public std::vector< parse_error > {
67 std::vector< parse_error > m_errors;
68 mutable std::string m_msg;
70 public:
71 parse_errors(void);
72 ~parse_errors(void) throw();
74 const char* what(void) const throw();
77 // ------------------------------------------------------------------------
78 // The "format_error" class.
79 // ------------------------------------------------------------------------
81 class format_error : public std::runtime_error {
82 public:
83 format_error(const std::string&);
86 // ------------------------------------------------------------------------
87 // The "token" class.
88 // ------------------------------------------------------------------------
90 typedef int token_type;
92 //!
93 //! \brief Representation of a read token.
94 //!
95 //! A pair that contains the information of a token read from a stream.
96 //! It contains the token's type and its associated data, if any.
97 //!
98 struct token {
99 bool m_inited;
100 size_t m_line;
101 token_type m_type;
102 std::string m_text;
104 public:
105 token(void);
106 token(size_t, const token_type&, const std::string& = "");
108 size_t lineno(void) const;
109 const token_type& type(void) const;
110 const std::string& text(void) const;
112 operator bool(void) const;
113 bool operator!(void) const;
116 // ------------------------------------------------------------------------
117 // The "tokenizer" class.
118 // ------------------------------------------------------------------------
121 //! \brief A stream tokenizer.
123 //! This template implements an extremely simple, line-oriented stream
124 //! tokenizer. It is only able to recognize one character-long delimiters,
125 //! random-length keywords, skip whitespace and, anything that does not
126 //! match these rules is supposed to be a word.
128 //! Parameter IS: The input stream's type.
130 template< class IS >
131 class tokenizer {
132 IS& m_is;
133 size_t m_lineno;
134 token m_la;
136 bool m_skipws;
137 token_type m_eof_type, m_nl_type, m_text_type;
139 std::map< char, token_type > m_delims_map;
140 std::string m_delims_str;
142 char m_quotech;
143 token_type m_quotetype;
145 std::map< std::string, token_type > m_keywords_map;
147 token_type alloc_type(void);
149 template< class TKZ >
150 friend
151 class parser;
153 public:
154 tokenizer(IS&, bool, const token_type&, const token_type&,
155 const token_type&, size_t = 1);
157 size_t lineno(void) const;
159 void add_delim(char, const token_type&);
160 void add_keyword(const std::string&, const token_type&);
161 void add_quote(char, const token_type&);
163 token next(void);
164 std::string rest_of_line(void);
167 template< class IS >
168 tokenizer< IS >::tokenizer(IS& p_is,
169 bool p_skipws,
170 const token_type& p_eof_type,
171 const token_type& p_nl_type,
172 const token_type& p_text_type,
173 size_t p_lineno) :
174 m_is(p_is),
175 m_lineno(p_lineno),
176 m_skipws(p_skipws),
177 m_eof_type(p_eof_type),
178 m_nl_type(p_nl_type),
179 m_text_type(p_text_type),
180 m_quotech(-1)
184 template< class IS >
185 size_t
186 tokenizer< IS >::lineno(void)
187 const
189 return m_lineno;
192 template< class IS >
193 void
194 tokenizer< IS >::add_delim(char delim, const token_type& type)
196 m_delims_map[delim] = type;
197 m_delims_str += delim;
200 template< class IS >
201 void
202 tokenizer< IS >::add_keyword(const std::string& keyword,
203 const token_type& type)
205 m_keywords_map[keyword] = type;
208 template< class IS >
209 void
210 tokenizer< IS >::add_quote(char ch, const token_type& type)
212 m_quotech = ch;
213 m_quotetype = type;
216 template< class IS >
217 token
218 tokenizer< IS >::next(void)
220 if (m_la) {
221 token t = m_la;
222 m_la = token();
223 if (t.type() == m_nl_type)
224 m_lineno++;
225 return t;
228 char ch;
229 std::string text;
231 bool done = false, quoted = false;
232 token t(m_lineno, m_eof_type, "<<EOF>>");
233 while (!done && m_is.get(ch).good()) {
234 if (ch == m_quotech) {
235 if (text.empty()) {
236 bool escaped = false;
237 while (!done && m_is.get(ch).good()) {
238 if (!escaped) {
239 if (ch == '\\')
240 escaped = true;
241 else if (ch == '\n') {
242 m_la = token(m_lineno, m_nl_type, "<<NEWLINE>>");
243 throw parse_error(t.lineno(),
244 "Missing double quotes before "
245 "end of line");
246 } else if (ch == m_quotech)
247 done = true;
248 else
249 text += ch;
250 } else {
251 text += ch;
252 escaped = false;
255 if (!m_is.good())
256 throw parse_error(t.lineno(),
257 "Missing double quotes before "
258 "end of file");
259 t = token(m_lineno, m_text_type, text);
260 quoted = true;
261 } else {
262 m_is.putback(ch);
263 done = true;
265 } else {
266 typename std::map< char, token_type >::const_iterator idelim;
267 idelim = m_delims_map.find(ch);
268 if (idelim != m_delims_map.end()) {
269 done = true;
270 if (text.empty())
271 t = token(m_lineno, (*idelim).second,
272 std::string("") + ch);
273 else
274 m_is.putback(ch);
275 } else if (ch == '\n') {
276 done = true;
277 if (text.empty())
278 t = token(m_lineno, m_nl_type, "<<NEWLINE>>");
279 else
280 m_is.putback(ch);
281 } else if (m_skipws && (ch == ' ' || ch == '\t')) {
282 if (!text.empty())
283 done = true;
284 } else
285 text += ch;
289 if (!quoted && !text.empty()) {
290 typename std::map< std::string, token_type >::const_iterator ikw;
291 ikw = m_keywords_map.find(text);
292 if (ikw != m_keywords_map.end())
293 t = token(m_lineno, (*ikw).second, text);
294 else
295 t = token(m_lineno, m_text_type, text);
298 if (t.type() == m_nl_type)
299 m_lineno++;
301 return t;
304 template< class IS >
305 std::string
306 tokenizer< IS >::rest_of_line(void)
308 std::string str;
309 while (m_is.good() && m_is.peek() != '\n')
310 str += m_is.get();
311 return str;
314 // ------------------------------------------------------------------------
315 // The "parser" class.
316 // ------------------------------------------------------------------------
318 template< class TKZ >
319 class parser {
320 TKZ& m_tkz;
321 token m_last;
322 parse_errors m_errors;
323 bool m_thrown;
325 public:
326 parser(TKZ& tkz);
327 ~parser(void);
329 bool good(void) const;
330 void add_error(const parse_error&);
331 bool has_errors(void) const;
333 token next(void);
334 std::string rest_of_line(void);
335 token reset(const token_type&);
337 token
338 expect(const token_type&,
339 const std::string&);
341 token
342 expect(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 std::string&);
352 token
353 expect(const token_type&,
354 const token_type&,
355 const token_type&,
356 const token_type&,
357 const std::string&);
359 token
360 expect(const token_type&,
361 const token_type&,
362 const token_type&,
363 const token_type&,
364 const token_type&,
365 const token_type&,
366 const token_type&,
367 const std::string&);
369 token
370 expect(const token_type&,
371 const token_type&,
372 const token_type&,
373 const token_type&,
374 const token_type&,
375 const token_type&,
376 const token_type&,
377 const token_type&,
378 const std::string&);
381 template< class TKZ >
382 parser< TKZ >::parser(TKZ& tkz) :
383 m_tkz(tkz),
384 m_thrown(false)
388 template< class TKZ >
389 parser< TKZ >::~parser(void)
391 if (!m_errors.empty() && !m_thrown)
392 throw m_errors;
395 template< class TKZ >
396 bool
397 parser< TKZ >::good(void)
398 const
400 return m_tkz.m_is.good();
403 template< class TKZ >
404 void
405 parser< TKZ >::add_error(const parse_error& pe)
407 m_errors.push_back(pe);
410 template< class TKZ >
411 bool
412 parser< TKZ >::has_errors(void)
413 const
415 return !m_errors.empty();
418 template< class TKZ >
419 token
420 parser< TKZ >::next(void)
422 token t = m_tkz.next();
424 m_last = t;
426 if (t.type() == m_tkz.m_eof_type) {
427 if (!m_errors.empty()) {
428 m_thrown = true;
429 throw m_errors;
433 return t;
436 template< class TKZ >
437 std::string
438 parser< TKZ >::rest_of_line(void)
440 return m_tkz.rest_of_line();
443 template< class TKZ >
444 token
445 parser< TKZ >::reset(const token_type& stop)
447 token t = m_last;
449 while (t.type() != m_tkz.m_eof_type && t.type() != stop)
450 t = next();
452 return t;
455 template< class TKZ >
456 token
457 parser< TKZ >::expect(const token_type& t1,
458 const std::string& textual)
460 token t = next();
462 if (t.type() != t1)
463 throw parse_error(t.lineno(),
464 "Unexpected token `" + t.text() +
465 "'; expected " + textual);
467 return t;
470 template< class TKZ >
471 token
472 parser< TKZ >::expect(const token_type& t1,
473 const token_type& t2,
474 const std::string& textual)
476 token t = next();
478 if (t.type() != t1 && t.type() != t2)
479 throw parse_error(t.lineno(),
480 "Unexpected token `" + t.text() +
481 "'; expected " + textual);
483 return t;
486 template< class TKZ >
487 token
488 parser< TKZ >::expect(const token_type& t1,
489 const token_type& t2,
490 const token_type& t3,
491 const std::string& textual)
493 token t = next();
495 if (t.type() != t1 && t.type() != t2 && t.type() != t3)
496 throw parse_error(t.lineno(),
497 "Unexpected token `" + t.text() +
498 "'; expected " + textual);
500 return t;
503 template< class TKZ >
504 token
505 parser< TKZ >::expect(const token_type& t1,
506 const token_type& t2,
507 const token_type& t3,
508 const token_type& t4,
509 const std::string& textual)
511 token t = next();
513 if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
514 t.type() != t4)
515 throw parse_error(t.lineno(),
516 "Unexpected token `" + t.text() +
517 "'; expected " + textual);
519 return t;
522 template< class TKZ >
523 token
524 parser< TKZ >::expect(const token_type& t1,
525 const token_type& t2,
526 const token_type& t3,
527 const token_type& t4,
528 const token_type& t5,
529 const token_type& t6,
530 const token_type& t7,
531 const std::string& textual)
533 token t = next();
535 if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
536 t.type() != t4 && t.type() != t5 && t.type() != t6 &&
537 t.type() != t7)
538 throw parse_error(t.lineno(),
539 "Unexpected token `" + t.text() +
540 "'; expected " + textual);
542 return t;
545 template< class TKZ >
546 token
547 parser< TKZ >::expect(const token_type& t1,
548 const token_type& t2,
549 const token_type& t3,
550 const token_type& t4,
551 const token_type& t5,
552 const token_type& t6,
553 const token_type& t7,
554 const token_type& t8,
555 const std::string& textual)
557 token t = next();
559 if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
560 t.type() != t4 && t.type() != t5 && t.type() != t6 &&
561 t.type() != t7 && t.type() != t8)
562 throw parse_error(t.lineno(),
563 "Unexpected token `" + t.text() +
564 "'; expected " + textual);
566 return t;
569 #define ATF_PARSER_CALLBACK(parser, func) \
570 do { \
571 if (!(parser).has_errors()) \
572 func; \
573 } while (false)
575 // ------------------------------------------------------------------------
576 // Header parsing.
577 // ------------------------------------------------------------------------
579 typedef std::map< std::string, std::string > attrs_map;
581 class header_entry {
582 std::string m_name;
583 std::string m_value;
584 attrs_map m_attrs;
586 public:
587 header_entry(void);
588 header_entry(const std::string&, const std::string&,
589 attrs_map = attrs_map());
591 const std::string& name(void) const;
592 const std::string& value(void) const;
593 const attrs_map& attrs(void) const;
594 bool has_attr(const std::string&) const;
595 const std::string& get_attr(const std::string&) const;
598 typedef std::map< std::string, header_entry > headers_map;
600 std::pair< size_t, headers_map > read_headers(std::istream&, size_t);
601 void write_headers(const headers_map&, std::ostream&);
602 void validate_content_type(const headers_map&, const std::string&, int);
604 } // namespace parser
605 } // namespace atf
607 #endif // !defined(_ATF_CXX_PARSER_HPP_)