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(TOOLS_PARSER_HPP)
31 #define TOOLS_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(TOOLS_PARSER_HPP)