/*============================================================================= 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 #include #include #include #include #include #include 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 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 inline void throw_(IteratorT where, ErrorDescrT descriptor) { boost::throw_exception( parser_error(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 struct assertive_parser : public unary > > { typedef assertive_parser self_t; typedef unary > base_t; typedef unary_parser_category parser_category_t; assertive_parser(ParserT const& parser, ErrorDescrT descriptor_) : base_t(parser), descriptor(descriptor_) {} template struct result { typedef typename parser_result::type type; }; template typename parser_result::type parse(ScannerT const& scan) const { typedef typename parser_result::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 expect_program(program_expected); // assertion expect_begin(begin_expected); // assertion 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 struct assertion { assertion(ErrorDescrT descriptor_) : descriptor(descriptor_) {} template assertive_parser operator()(ParserT const& parser) const { return assertive_parser(parser, descriptor); } ErrorDescrT descriptor; }; /////////////////////////////////////////////////////////////////////////// // // error_status // // 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 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 // 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 // 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 object (see above). // /////////////////////////////////////////////////////////////////////////// namespace impl { template RT fallback_parser_parse(ParserT const& p, ScannerT const& scan); } template struct fallback_parser : public unary > > { typedef fallback_parser self_t; typedef ErrorDescrT error_descr_t; typedef unary > base_t; typedef unary_parser_category parser_category_t; fallback_parser(ParserT const& parser, HandlerT const& handler_) : base_t(parser), handler(handler_) {} template struct result { typedef typename parser_result::type type; }; template typename parser_result::type parse(ScannerT const& scan) const { typedef typename parser_result::type result_t; return impl::fallback_parser_parse(*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 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 struct guard_gen : public unary { typedef guard parser_generator_t; typedef unary_parser_category parser_category_t; guard_gen(ParserT const& p) : unary(p) {} template fallback_parser operator[](HandlerT const& handler) const { return fallback_parser (this->subject(), handler); } }; template struct guard { template struct result { typedef guard_gen type; }; template static guard_gen generate(ParserT const& parser) { return guard_gen(parser); } template guard_gen operator()(ParserT const& parser) const { return guard_gen(parser); } }; BOOST_SPIRIT_CLASSIC_NAMESPACE_END }} // namespace BOOST_SPIRIT_CLASSIC_NS #include #endif