2 // Automated Testing Framework (atf)
4 // Copyright (c) 2007, 2008 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_
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
;
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
;
68 ~parse_errors(void) throw();
70 const char* what(void) const throw();
73 // ------------------------------------------------------------------------
75 // ------------------------------------------------------------------------
77 typedef int token_type
;
80 //! \brief Representation of a read token.
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.
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.
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
;
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
>
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
&);
151 std::string
rest_of_line(void);
155 tokenizer
< IS
>::tokenizer(IS
& p_is
,
157 const token_type
& p_eof_type
,
158 const token_type
& p_nl_type
,
159 const token_type
& p_text_type
,
164 m_eof_type(p_eof_type
),
165 m_nl_type(p_nl_type
),
166 m_text_type(p_text_type
),
173 tokenizer
< IS
>::lineno(void)
181 tokenizer
< IS
>::add_delim(char delim
, const token_type
& type
)
183 m_delims_map
[delim
] = type
;
184 m_delims_str
+= delim
;
189 tokenizer
< IS
>::add_keyword(const std::string
& keyword
,
190 const token_type
& type
)
192 m_keywords_map
[keyword
] = type
;
197 tokenizer
< IS
>::add_quote(char ch
, const token_type
& type
)
205 tokenizer
< IS
>::next(void)
210 if (t
.type() == m_nl_type
)
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
) {
223 bool escaped
= false;
224 while (!done
&& m_is
.get(ch
).good()) {
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 "
233 } else if (ch
== m_quotech
)
243 throw parse_error(t
.lineno(),
244 "Missing double quotes before "
246 t
= token(m_lineno
, m_text_type
, text
);
253 typename
std::map
< char, token_type
>::const_iterator idelim
;
254 idelim
= m_delims_map
.find(ch
);
255 if (idelim
!= m_delims_map
.end()) {
258 t
= token(m_lineno
, (*idelim
).second
,
259 std::string("") + ch
);
262 } else if (ch
== '\n') {
265 t
= token(m_lineno
, m_nl_type
, "<<NEWLINE>>");
268 } else if (m_skipws
&& (ch
== ' ' || ch
== '\t')) {
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
);
282 t
= token(m_lineno
, m_text_type
, text
);
285 if (t
.type() == m_nl_type
)
293 tokenizer
< IS
>::rest_of_line(void)
296 while (m_is
.good() && m_is
.peek() != '\n')
301 // ------------------------------------------------------------------------
302 // The "parser" class.
303 // ------------------------------------------------------------------------
305 template< class TKZ
>
309 parse_errors m_errors
;
316 bool good(void) const;
317 void add_error(const parse_error
&);
318 bool has_errors(void) const;
321 std::string
rest_of_line(void);
322 token
reset(const token_type
&);
325 expect(const token_type
&,
329 expect(const token_type
&,
334 expect(const token_type
&,
340 expect(const token_type
&,
347 expect(const token_type
&,
357 template< class TKZ
>
358 parser
< TKZ
>::parser(TKZ
& tkz
) :
364 template< class TKZ
>
365 parser
< TKZ
>::~parser(void)
367 if (!m_errors
.empty() && !m_thrown
)
371 template< class TKZ
>
373 parser
< TKZ
>::good(void)
376 return m_tkz
.m_is
.good();
379 template< class TKZ
>
381 parser
< TKZ
>::add_error(const parse_error
& pe
)
383 m_errors
.push_back(pe
);
386 template< class TKZ
>
388 parser
< TKZ
>::has_errors(void)
391 return !m_errors
.empty();
394 template< class TKZ
>
396 parser
< TKZ
>::next(void)
398 token t
= m_tkz
.next();
402 if (t
.type() == m_tkz
.m_eof_type
) {
403 if (!m_errors
.empty()) {
412 template< class TKZ
>
414 parser
< TKZ
>::rest_of_line(void)
416 return m_tkz
.rest_of_line();
419 template< class TKZ
>
421 parser
< TKZ
>::reset(const token_type
& stop
)
425 while (t
.type() != m_tkz
.m_eof_type
&& t
.type() != stop
)
431 template< class TKZ
>
433 parser
< TKZ
>::expect(const token_type
& t1
,
434 const std::string
& textual
)
439 throw parse_error(t
.lineno(),
440 "Unexpected token `" + t
.text() +
441 "'; expected " + textual
);
446 template< class TKZ
>
448 parser
< TKZ
>::expect(const token_type
& t1
,
449 const token_type
& t2
,
450 const std::string
& textual
)
454 if (t
.type() != t1
&& t
.type() != t2
)
455 throw parse_error(t
.lineno(),
456 "Unexpected token `" + t
.text() +
457 "'; expected " + textual
);
462 template< class TKZ
>
464 parser
< TKZ
>::expect(const token_type
& t1
,
465 const token_type
& t2
,
466 const token_type
& t3
,
467 const std::string
& textual
)
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
);
479 template< class TKZ
>
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
)
489 if (t
.type() != t1
&& t
.type() != t2
&& t
.type() != t3
&&
491 throw parse_error(t
.lineno(),
492 "Unexpected token `" + t
.text() +
493 "'; expected " + textual
);
498 template< class TKZ
>
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
)
511 if (t
.type() != t1
&& t
.type() != t2
&& t
.type() != t3
&&
512 t
.type() != t4
&& t
.type() != t5
&& t
.type() != t6
&&
514 throw parse_error(t
.lineno(),
515 "Unexpected token `" + t
.text() +
516 "'; expected " + textual
);
521 } // namespace parser
524 #endif // !defined(_ATF_CXX_PARSER_HPP_)