| /*============================================================================= |
| Copyright (c) 2001-2003 Joel de Guzman |
| http://spirit.sourceforge.net/ |
| |
| Distributed under the Boost Software License, Version 1.0. (See accompanying |
| file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| =============================================================================*/ |
| #ifndef BOOST_SPIRIT_EXCEPTIONS_HPP |
| #define BOOST_SPIRIT_EXCEPTIONS_HPP |
| |
| #include <boost/config.hpp> |
| #include <boost/throw_exception.hpp> |
| #include <boost/spirit/home/classic/namespace.hpp> |
| #include <boost/spirit/home/classic/core/parser.hpp> |
| #include <boost/spirit/home/classic/core/composite/composite.hpp> |
| #include <exception> |
| |
| #include <boost/spirit/home/classic/error_handling/exceptions_fwd.hpp> |
| |
| namespace boost { namespace spirit { |
| |
| BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // |
| // parser_error_base class |
| // |
| // This is the base class of parser_error (see below). This may be |
| // used to catch any type of parser error. |
| // |
| // This exception shouldn't propagate outside the parser. However to |
| // avoid quirks of many platforms/implementations which fall outside |
| // the C++ standard, we derive parser_error_base from std::exception |
| // to allow a single catch handler to catch all exceptions. |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| class parser_error_base : public std::exception |
| { |
| protected: |
| |
| parser_error_base() {} |
| virtual ~parser_error_base() throw() {} |
| |
| public: |
| |
| parser_error_base(parser_error_base const& rhs) |
| : std::exception(rhs) {} |
| parser_error_base& operator=(parser_error_base const&) |
| { |
| return *this; |
| } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // |
| // parser_error class |
| // |
| // Generic parser exception class. This is the base class for all |
| // parser exceptions. The exception holds the iterator position |
| // where the error was encountered in its member variable "where". |
| // The parser_error also holds information regarding the error |
| // (error descriptor) in its member variable "descriptor". |
| // |
| // The throw_ function creates and throws a parser_error given |
| // an iterator and an error descriptor. |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename ErrorDescrT, typename IteratorT> |
| struct parser_error : public parser_error_base |
| { |
| typedef ErrorDescrT error_descr_t; |
| typedef IteratorT iterator_t; |
| |
| parser_error(IteratorT where_, ErrorDescrT descriptor_) |
| : where(where_), descriptor(descriptor_) {} |
| |
| parser_error(parser_error const& rhs) |
| : parser_error_base(rhs) |
| , where(rhs.where), descriptor(rhs.descriptor) {} |
| |
| parser_error& |
| operator=(parser_error const& rhs) |
| { |
| where = rhs.where; |
| descriptor = rhs.descriptor; |
| return *this; |
| } |
| |
| virtual |
| ~parser_error() throw() {} |
| |
| virtual const char* |
| what() const throw() |
| { |
| return "BOOST_SPIRIT_CLASSIC_NS::parser_error"; |
| } |
| |
| IteratorT where; |
| ErrorDescrT descriptor; |
| }; |
| |
| ////////////////////////////////// |
| template <typename ErrorDescrT, typename IteratorT> |
| inline void |
| throw_(IteratorT where, ErrorDescrT descriptor) |
| { |
| boost::throw_exception( |
| parser_error<ErrorDescrT, IteratorT>(where, descriptor)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // |
| // assertive_parser class |
| // |
| // An assertive_parser class is a parser that throws an exception |
| // in response to a parsing failure. The assertive_parser throws a |
| // parser_error exception rather than returning an unsuccessful |
| // match to signal that the parser failed to match the input. |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename ErrorDescrT, typename ParserT> |
| struct assertive_parser |
| : public unary<ParserT, parser<assertive_parser<ErrorDescrT, ParserT> > > |
| { |
| typedef assertive_parser<ErrorDescrT, ParserT> self_t; |
| typedef unary<ParserT, parser<self_t> > base_t; |
| typedef unary_parser_category parser_category_t; |
| |
| assertive_parser(ParserT const& parser, ErrorDescrT descriptor_) |
| : base_t(parser), descriptor(descriptor_) {} |
| |
| template <typename ScannerT> |
| struct result |
| { |
| typedef typename parser_result<ParserT, ScannerT>::type type; |
| }; |
| |
| template <typename ScannerT> |
| typename parser_result<self_t, ScannerT>::type |
| parse(ScannerT const& scan) const |
| { |
| typedef typename parser_result<ParserT, ScannerT>::type result_t; |
| typedef typename ScannerT::iterator_t iterator_t; |
| |
| result_t hit = this->subject().parse(scan); |
| if (!hit) |
| { |
| throw_(scan.first, descriptor); |
| } |
| return hit; |
| } |
| |
| ErrorDescrT descriptor; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // |
| // assertion class |
| // |
| // assertive_parsers are never instantiated directly. The assertion |
| // class is used to indirectly create an assertive_parser object. |
| // Before declaring the grammar, we declare some assertion objects. |
| // Examples: |
| // |
| // enum Errors |
| // { |
| // program_expected, begin_expected, end_expected |
| // }; |
| // |
| // assertion<Errors> expect_program(program_expected); |
| // assertion<Errors> expect_begin(begin_expected); |
| // assertion<Errors> expect_end(end_expected); |
| // |
| // Now, we can use these assertions as wrappers around parsers: |
| // |
| // expect_end(str_p("end")) |
| // |
| // Take note that although the example uses enums to hold the |
| // information regarding the error (error desccriptor), we are free |
| // to use other types such as integers and strings. Enums are |
| // convenient for error handlers to easily catch since C++ treats |
| // enums as unique types. |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename ErrorDescrT> |
| struct assertion |
| { |
| assertion(ErrorDescrT descriptor_) |
| : descriptor(descriptor_) {} |
| |
| template <typename ParserT> |
| assertive_parser<ErrorDescrT, ParserT> |
| operator()(ParserT const& parser) const |
| { |
| return assertive_parser<ErrorDescrT, ParserT>(parser, descriptor); |
| } |
| |
| ErrorDescrT descriptor; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // |
| // error_status<T> |
| // |
| // Where T is an attribute type compatible with the match attribute |
| // of the fallback_parser's subject (defaults to nil_t). The class |
| // error_status reports the result of an error handler (see |
| // fallback_parser). result can be one of: |
| // |
| // fail: quit and fail (return a no_match) |
| // retry: attempt error recovery, possibly moving the scanner |
| // accept: force success returning a matching length, moving |
| // the scanner appropriately and returning an attribute |
| // value |
| // rethrow: rethrows the error. |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename T> |
| struct error_status |
| { |
| enum result_t { fail, retry, accept, rethrow }; |
| |
| error_status( |
| result_t result_ = fail, |
| std::ptrdiff_t length_ = -1, |
| T const& value_ = T()) |
| : result(result_), length(length_), value(value_) {} |
| |
| result_t result; |
| std::ptrdiff_t length; |
| T value; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // |
| // fallback_parser class |
| // |
| // Handles exceptions of type parser_error<ErrorDescrT, IteratorT> |
| // thrown somewhere inside its embedded ParserT object. The class |
| // sets up a try block before delegating parsing to its subject. |
| // When an exception is caught, the catch block then calls the |
| // HandlerT object. HandlerT may be a function or a functor (with |
| // an operator() member function) compatible with the interface: |
| // |
| // error_status<T> |
| // handler(ScannerT const& scan, ErrorT error); |
| // |
| // Where scan points to the scanner state prior to parsing and error |
| // is the error that arose (see parser_error). The handler must |
| // return an error_status<T> object (see above). |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| namespace impl |
| { |
| template <typename RT, typename ParserT, typename ScannerT> |
| RT fallback_parser_parse(ParserT const& p, ScannerT const& scan); |
| } |
| |
| template <typename ErrorDescrT, typename ParserT, typename HandlerT> |
| struct fallback_parser |
| : public unary<ParserT, |
| parser<fallback_parser<ErrorDescrT, ParserT, HandlerT> > > |
| { |
| typedef fallback_parser<ErrorDescrT, ParserT, HandlerT> |
| self_t; |
| typedef ErrorDescrT |
| error_descr_t; |
| typedef unary<ParserT, parser<self_t> > |
| base_t; |
| typedef unary_parser_category |
| parser_category_t; |
| |
| fallback_parser(ParserT const& parser, HandlerT const& handler_) |
| : base_t(parser), handler(handler_) {} |
| |
| template <typename ScannerT> |
| struct result |
| { |
| typedef typename parser_result<ParserT, ScannerT>::type type; |
| }; |
| |
| template <typename ScannerT> |
| typename parser_result<self_t, ScannerT>::type |
| parse(ScannerT const& scan) const |
| { |
| typedef typename parser_result<self_t, ScannerT>::type result_t; |
| return impl::fallback_parser_parse<result_t>(*this, scan); |
| } |
| |
| HandlerT handler; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // |
| // guard class |
| // |
| // fallback_parser objects are not instantiated directly. The guard |
| // class is used to indirectly create a fallback_parser object. |
| // guards are typically predeclared just like assertions (see the |
| // assertion class above; the example extends the previous example |
| // introduced in the assertion class above): |
| // |
| // guard<Errors> my_guard; |
| // |
| // Errors, in this example is the error descriptor type we want to |
| // detect; This is essentially the ErrorDescrT template parameter |
| // of the fallback_parser class. |
| // |
| // my_guard may now be used in a grammar declaration as: |
| // |
| // my_guard(p)[h] |
| // |
| // where p is a parser, h is a function or functor compatible with |
| // fallback_parser's HandlerT (see above). |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename ErrorDescrT, typename ParserT> |
| struct guard_gen : public unary<ParserT, nil_t> |
| { |
| typedef guard<ErrorDescrT> parser_generator_t; |
| typedef unary_parser_category parser_category_t; |
| |
| guard_gen(ParserT const& p) |
| : unary<ParserT, nil_t>(p) {} |
| |
| template <typename HandlerT> |
| fallback_parser<ErrorDescrT, ParserT, HandlerT> |
| operator[](HandlerT const& handler) const |
| { |
| return fallback_parser<ErrorDescrT, ParserT, HandlerT> |
| (this->subject(), handler); |
| } |
| }; |
| |
| template <typename ErrorDescrT> |
| struct guard |
| { |
| template <typename ParserT> |
| struct result |
| { |
| typedef guard_gen<ErrorDescrT, ParserT> type; |
| }; |
| |
| template <typename ParserT> |
| static guard_gen<ErrorDescrT, ParserT> |
| generate(ParserT const& parser) |
| { |
| return guard_gen<ErrorDescrT, ParserT>(parser); |
| } |
| |
| template <typename ParserT> |
| guard_gen<ErrorDescrT, ParserT> |
| operator()(ParserT const& parser) const |
| { |
| return guard_gen<ErrorDescrT, ParserT>(parser); |
| } |
| }; |
| |
| BOOST_SPIRIT_CLASSIC_NAMESPACE_END |
| |
| }} // namespace BOOST_SPIRIT_CLASSIC_NS |
| |
| #include <boost/spirit/home/classic/error_handling/impl/exceptions.ipp> |
| #endif |
| |