2 // Automated Testing Framework (atf)
4 // Copyright (c) 2007 The NetBSD Foundation, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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_
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;
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;
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 {
83 format_error(const std::string&);
86 // ------------------------------------------------------------------------
88 // ------------------------------------------------------------------------
90 typedef int token_type;
93 //! \brief Representation of a read token.
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.
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.
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;
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 >
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&);
164 std::string rest_of_line(void);
168 tokenizer< IS >::tokenizer(IS& p_is,
170 const token_type& p_eof_type,
171 const token_type& p_nl_type,
172 const token_type& p_text_type,
177 m_eof_type(p_eof_type),
178 m_nl_type(p_nl_type),
179 m_text_type(p_text_type),
186 tokenizer< IS >::lineno(void)
194 tokenizer< IS >::add_delim(char delim, const token_type& type)
196 m_delims_map[delim] = type;
197 m_delims_str += delim;
202 tokenizer< IS >::add_keyword(const std::string& keyword,
203 const token_type& type)
205 m_keywords_map[keyword] = type;
210 tokenizer< IS >::add_quote(char ch, const token_type& type)
218 tokenizer< IS >::next(void)
223 if (t.type() == m_nl_type)
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) {
236 bool escaped = false;
237 while (!done && m_is.get(ch).good()) {
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 "
246 } else if (ch == m_quotech)
256 throw parse_error(t.lineno(),
257 "Missing double quotes before "
259 t = token(m_lineno, m_text_type, text);
266 typename std::map< char, token_type >::const_iterator idelim;
267 idelim = m_delims_map.find(ch);
268 if (idelim != m_delims_map.end()) {
271 t = token(m_lineno, (*idelim).second,
272 std::string("") + ch);
275 } else if (ch == '\n') {
278 t = token(m_lineno, m_nl_type, "<<NEWLINE>>");
281 } else if (m_skipws && (ch == ' ' || ch == '\t')) {
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);
295 t = token(m_lineno, m_text_type, text);
298 if (t.type() == m_nl_type)
306 tokenizer< IS >::rest_of_line(void)
309 while (m_is.good() && m_is.peek() != '\n')
314 // ------------------------------------------------------------------------
315 // The "parser" class.
316 // ------------------------------------------------------------------------
318 template< class TKZ >
322 parse_errors m_errors;
329 bool good(void) const;
330 void add_error(const parse_error&);
331 bool has_errors(void) const;
334 std::string rest_of_line(void);
335 token reset(const token_type&);
338 expect(const token_type&,
342 expect(const token_type&,
347 expect(const token_type&,
353 expect(const token_type&,
360 expect(const token_type&,
370 expect(const token_type&,
381 template< class TKZ >
382 parser< TKZ >::parser(TKZ& tkz) :
388 template< class TKZ >
389 parser< TKZ >::~parser(void)
391 if (!m_errors.empty() && !m_thrown)
395 template< class TKZ >
397 parser< TKZ >::good(void)
400 return m_tkz.m_is.good();
403 template< class TKZ >
405 parser< TKZ >::add_error(const parse_error& pe)
407 m_errors.push_back(pe);
410 template< class TKZ >
412 parser< TKZ >::has_errors(void)
415 return !m_errors.empty();
418 template< class TKZ >
420 parser< TKZ >::next(void)
422 token t = m_tkz.next();
426 if (t.type() == m_tkz.m_eof_type) {
427 if (!m_errors.empty()) {
436 template< class TKZ >
438 parser< TKZ >::rest_of_line(void)
440 return m_tkz.rest_of_line();
443 template< class TKZ >
445 parser< TKZ >::reset(const token_type& stop)
449 while (t.type() != m_tkz.m_eof_type && t.type() != stop)
455 template< class TKZ >
457 parser< TKZ >::expect(const token_type& t1,
458 const std::string& textual)
463 throw parse_error(t.lineno(),
464 "Unexpected token `" + t.text() +
465 "'; expected " + textual);
470 template< class TKZ >
472 parser< TKZ >::expect(const token_type& t1,
473 const token_type& t2,
474 const std::string& textual)
478 if (t.type() != t1 && t.type() != t2)
479 throw parse_error(t.lineno(),
480 "Unexpected token `" + t.text() +
481 "'; expected " + textual);
486 template< class TKZ >
488 parser< TKZ >::expect(const token_type& t1,
489 const token_type& t2,
490 const token_type& t3,
491 const std::string& textual)
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);
503 template< class TKZ >
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)
513 if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
515 throw parse_error(t.lineno(),
516 "Unexpected token `" + t.text() +
517 "'; expected " + textual);
522 template< class TKZ >
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)
535 if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
536 t.type() != t4 && t.type() != t5 && t.type() != t6 &&
538 throw parse_error(t.lineno(),
539 "Unexpected token `" + t.text() +
540 "'; expected " + textual);
545 template< class TKZ >
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)
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);
569 #define ATF_PARSER_CALLBACK(parser, func) \
571 if (!(parser).has_errors()) \
575 // ------------------------------------------------------------------------
577 // ------------------------------------------------------------------------
579 typedef std::map< std::string, std::string > attrs_map;
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
607 #endif // !defined(_ATF_CXX_PARSER_HPP_)