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