• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2003 Joel de Guzman
3     http://spirit.sourceforge.net/
4 
5   Distributed under the Boost Software License, Version 1.0. (See accompanying
6   file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 #ifndef BOOST_SPIRIT_EXCEPTIONS_HPP
9 #define BOOST_SPIRIT_EXCEPTIONS_HPP
10 
11 #include <boost/config.hpp>
12 #include <boost/throw_exception.hpp>
13 #include <boost/spirit/home/classic/namespace.hpp>
14 #include <boost/spirit/home/classic/core/parser.hpp>
15 #include <boost/spirit/home/classic/core/composite/composite.hpp>
16 #include <exception>
17 
18 #include <boost/spirit/home/classic/error_handling/exceptions_fwd.hpp>
19 
20 namespace boost { namespace spirit {
21 
22 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
23 
24     ///////////////////////////////////////////////////////////////////////////
25     //
26     //  parser_error_base class
27     //
28     //      This is the base class of parser_error (see below). This may be
29     //      used to catch any type of parser error.
30     //
31     //      This exception shouldn't propagate outside the parser. However to
32     //      avoid quirks of many platforms/implementations which fall outside
33     //      the C++ standard, we derive parser_error_base from std::exception
34     //      to allow a single catch handler to catch all exceptions.
35     //
36     ///////////////////////////////////////////////////////////////////////////
37     class BOOST_SYMBOL_VISIBLE parser_error_base : public std::exception
38     {
39     protected:
40 
parser_error_base()41         parser_error_base() {}
~parser_error_base()42         virtual ~parser_error_base() BOOST_NOEXCEPT_OR_NOTHROW {}
43 
44     public:
45 
parser_error_base(parser_error_base const & rhs)46         parser_error_base(parser_error_base const& rhs)
47             : std::exception(rhs) {}
operator =(parser_error_base const &)48         parser_error_base& operator=(parser_error_base const&)
49         {
50             return *this;
51         }
52     };
53 
54     ///////////////////////////////////////////////////////////////////////////
55     //
56     //  parser_error class
57     //
58     //      Generic parser exception class. This is the base class for all
59     //      parser exceptions. The exception holds the iterator position
60     //      where the error was encountered in its member variable "where".
61     //      The parser_error also holds information regarding the error
62     //      (error descriptor) in its member variable "descriptor".
63     //
64     //      The throw_ function creates and throws a parser_error given
65     //      an iterator and an error descriptor.
66     //
67     ///////////////////////////////////////////////////////////////////////////
68     template <typename ErrorDescrT, typename IteratorT>
69     struct parser_error : public parser_error_base
70     {
71         typedef ErrorDescrT error_descr_t;
72         typedef IteratorT iterator_t;
73 
parser_errorboost::spirit::parser_error74         parser_error(IteratorT where_, ErrorDescrT descriptor_)
75         : where(where_), descriptor(descriptor_) {}
76 
parser_errorboost::spirit::parser_error77         parser_error(parser_error const& rhs)
78         : parser_error_base(rhs)
79         , where(rhs.where), descriptor(rhs.descriptor) {}
80 
81         parser_error&
operator =boost::spirit::parser_error82         operator=(parser_error const& rhs)
83         {
84             where = rhs.where;
85             descriptor = rhs.descriptor;
86             return *this;
87         }
88 
89         virtual
~parser_errorboost::spirit::parser_error90         ~parser_error() BOOST_NOEXCEPT_OR_NOTHROW {}
91 
92         virtual const char*
whatboost::spirit::parser_error93         what() const BOOST_NOEXCEPT_OR_NOTHROW
94         {
95             return "BOOST_SPIRIT_CLASSIC_NS::parser_error";
96         }
97 
98         IteratorT where;
99         ErrorDescrT descriptor;
100     };
101 
102     //////////////////////////////////
103     template <typename ErrorDescrT, typename IteratorT>
104     inline void
throw_(IteratorT where,ErrorDescrT descriptor)105     throw_(IteratorT where, ErrorDescrT descriptor)
106     {
107          boost::throw_exception(
108             parser_error<ErrorDescrT, IteratorT>(where, descriptor));
109     }
110 
111     ///////////////////////////////////////////////////////////////////////////
112     //
113     //  assertive_parser class
114     //
115     //      An assertive_parser class is a parser that throws an exception
116     //      in response to a parsing failure. The assertive_parser throws a
117     //      parser_error exception rather than returning an unsuccessful
118     //      match to signal that the parser failed to match the input.
119     //
120     ///////////////////////////////////////////////////////////////////////////
121     template <typename ErrorDescrT, typename ParserT>
122     struct assertive_parser
123     :   public unary<ParserT, parser<assertive_parser<ErrorDescrT, ParserT> > >
124     {
125         typedef assertive_parser<ErrorDescrT, ParserT>  self_t;
126         typedef unary<ParserT, parser<self_t> >         base_t;
127         typedef unary_parser_category                   parser_category_t;
128 
assertive_parserboost::spirit::assertive_parser129         assertive_parser(ParserT const& parser, ErrorDescrT descriptor_)
130         : base_t(parser), descriptor(descriptor_) {}
131 
132         template <typename ScannerT>
133         struct result
134         {
135             typedef typename parser_result<ParserT, ScannerT>::type type;
136         };
137 
138         template <typename ScannerT>
139         typename parser_result<self_t, ScannerT>::type
parseboost::spirit::assertive_parser140         parse(ScannerT const& scan) const
141         {
142             typedef typename parser_result<ParserT, ScannerT>::type result_t;
143 
144             result_t hit = this->subject().parse(scan);
145             if (!hit)
146             {
147                 throw_(scan.first, descriptor);
148             }
149             return hit;
150         }
151 
152         ErrorDescrT descriptor;
153     };
154 
155     ///////////////////////////////////////////////////////////////////////////
156     //
157     //  assertion class
158     //
159     //      assertive_parsers are never instantiated directly. The assertion
160     //      class is used to indirectly create an assertive_parser object.
161     //      Before declaring the grammar, we declare some assertion objects.
162     //      Examples:
163     //
164     //          enum Errors
165     //          {
166     //              program_expected, begin_expected, end_expected
167     //          };
168     //
169     //          assertion<Errors>   expect_program(program_expected);
170     //          assertion<Errors>   expect_begin(begin_expected);
171     //          assertion<Errors>   expect_end(end_expected);
172     //
173     //      Now, we can use these assertions as wrappers around parsers:
174     //
175     //          expect_end(str_p("end"))
176     //
177     //      Take note that although the example uses enums to hold the
178     //      information regarding the error (error desccriptor), we are free
179     //      to use other types such as integers and strings. Enums are
180     //      convenient for error handlers to easily catch since C++ treats
181     //      enums as unique types.
182     //
183     ///////////////////////////////////////////////////////////////////////////
184     template <typename ErrorDescrT>
185     struct assertion
186     {
assertionboost::spirit::assertion187         assertion(ErrorDescrT descriptor_)
188         : descriptor(descriptor_) {}
189 
190         template <typename ParserT>
191         assertive_parser<ErrorDescrT, ParserT>
operator ()boost::spirit::assertion192         operator()(ParserT const& parser) const
193         {
194             return assertive_parser<ErrorDescrT, ParserT>(parser, descriptor);
195         }
196 
197         ErrorDescrT descriptor;
198     };
199 
200     ///////////////////////////////////////////////////////////////////////////
201     //
202     //  error_status<T>
203     //
204     //      Where T is an attribute type compatible with the match attribute
205     //      of the fallback_parser's subject (defaults to nil_t). The class
206     //      error_status reports the result of an error handler (see
207     //      fallback_parser). result can be one of:
208     //
209     //          fail:       quit and fail (return a no_match)
210     //          retry:      attempt error recovery, possibly moving the scanner
211     //          accept:     force success returning a matching length, moving
212     //                      the scanner appropriately and returning an attribute
213     //                      value
214     //          rethrow:    rethrows the error.
215     //
216     ///////////////////////////////////////////////////////////////////////////
217     template <typename T>
218     struct error_status
219     {
220         enum result_t { fail, retry, accept, rethrow };
221 
error_statusboost::spirit::error_status222         error_status(
223             result_t result_ = fail,
224             std::ptrdiff_t length_ = -1,
225             T const& value_ = T())
226         : result(result_), length(length_), value(value_) {}
227 
228         result_t        result;
229         std::ptrdiff_t  length;
230         T               value;
231     };
232 
233     ///////////////////////////////////////////////////////////////////////////
234     //
235     //  fallback_parser class
236     //
237     //      Handles exceptions of type parser_error<ErrorDescrT, IteratorT>
238     //      thrown somewhere inside its embedded ParserT object. The class
239     //      sets up a try block before delegating parsing to its subject.
240     //      When an exception is caught, the catch block then calls the
241     //      HandlerT object. HandlerT may be a function or a functor (with
242     //      an operator() member function) compatible with the interface:
243     //
244     //          error_status<T>
245     //          handler(ScannerT const& scan, ErrorT error);
246     //
247     //      Where scan points to the scanner state prior to parsing and error
248     //      is the error that arose (see parser_error). The handler must
249     //      return an error_status<T> object (see above).
250     //
251     ///////////////////////////////////////////////////////////////////////////
252     namespace impl
253     {
254         template <typename RT, typename ParserT, typename ScannerT>
255         RT fallback_parser_parse(ParserT const& p, ScannerT const& scan);
256     }
257 
258     template <typename ErrorDescrT, typename ParserT, typename HandlerT>
259     struct fallback_parser
260     :   public unary<ParserT,
261         parser<fallback_parser<ErrorDescrT, ParserT, HandlerT> > >
262     {
263         typedef fallback_parser<ErrorDescrT, ParserT, HandlerT>
264             self_t;
265         typedef ErrorDescrT
266             error_descr_t;
267         typedef unary<ParserT, parser<self_t> >
268             base_t;
269         typedef unary_parser_category
270             parser_category_t;
271 
fallback_parserboost::spirit::fallback_parser272         fallback_parser(ParserT const& parser, HandlerT const& handler_)
273         : base_t(parser), handler(handler_) {}
274 
275         template <typename ScannerT>
276         struct result
277         {
278             typedef typename parser_result<ParserT, ScannerT>::type type;
279         };
280 
281         template <typename ScannerT>
282         typename parser_result<self_t, ScannerT>::type
parseboost::spirit::fallback_parser283         parse(ScannerT const& scan) const
284         {
285             typedef typename parser_result<self_t, ScannerT>::type result_t;
286             return impl::fallback_parser_parse<result_t>(*this, scan);
287         }
288 
289         HandlerT handler;
290     };
291 
292     ///////////////////////////////////////////////////////////////////////////
293     //
294     //  guard class
295     //
296     //      fallback_parser objects are not instantiated directly. The guard
297     //      class is used to indirectly create a fallback_parser object.
298     //      guards are typically predeclared just like assertions (see the
299     //      assertion class above; the example extends the previous example
300     //      introduced in the assertion class above):
301     //
302     //          guard<Errors>   my_guard;
303     //
304     //      Errors, in this example is the error descriptor type we want to
305     //      detect; This is essentially the ErrorDescrT template parameter
306     //      of the fallback_parser class.
307     //
308     //      my_guard may now be used in a grammar declaration as:
309     //
310     //          my_guard(p)[h]
311     //
312     //      where p is a parser, h is a function or functor compatible with
313     //      fallback_parser's HandlerT (see above).
314     //
315     ///////////////////////////////////////////////////////////////////////////
316     template <typename ErrorDescrT, typename ParserT>
317     struct guard_gen : public unary<ParserT, nil_t>
318     {
319         typedef guard<ErrorDescrT>      parser_generator_t;
320         typedef unary_parser_category   parser_category_t;
321 
guard_genboost::spirit::guard_gen322         guard_gen(ParserT const& p)
323         : unary<ParserT, nil_t>(p) {}
324 
325         template <typename HandlerT>
326         fallback_parser<ErrorDescrT, ParserT, HandlerT>
operator []boost::spirit::guard_gen327         operator[](HandlerT const& handler) const
328         {
329             return fallback_parser<ErrorDescrT, ParserT, HandlerT>
330                 (this->subject(), handler);
331         }
332     };
333 
334     template <typename ErrorDescrT>
335     struct guard
336     {
337         template <typename ParserT>
338         struct result
339         {
340             typedef guard_gen<ErrorDescrT, ParserT> type;
341         };
342 
343         template <typename ParserT>
344         static guard_gen<ErrorDescrT, ParserT>
generateboost::spirit::guard345         generate(ParserT const& parser)
346         {
347             return guard_gen<ErrorDescrT, ParserT>(parser);
348         }
349 
350         template <typename ParserT>
351         guard_gen<ErrorDescrT, ParserT>
operator ()boost::spirit::guard352         operator()(ParserT const& parser) const
353         {
354             return guard_gen<ErrorDescrT, ParserT>(parser);
355         }
356     };
357 
358 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
359 
360 }} // namespace BOOST_SPIRIT_CLASSIC_NS
361 
362 #include <boost/spirit/home/classic/error_handling/impl/exceptions.ipp>
363 #endif
364 
365