1 /*============================================================================= 2 Copyright (c) 2010-2011 Daniel James 3 Copyright (c) 2003 Martin Wille 4 http://spirit.sourceforge.net/ 5 6 Distributed under the Boost Software License, Version 1.0. (See accompanying 7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 =============================================================================*/ 9 10 // Some custom parsers for use in quickbook. 11 12 #ifndef BOOST_QUICKBOOK_PARSERS_HPP 13 #define BOOST_QUICKBOOK_PARSERS_HPP 14 15 #include <boost/spirit/include/classic_core.hpp> 16 #include <boost/spirit/include/classic_nil.hpp> 17 #include <boost/spirit/include/phoenix1_binders.hpp> 18 #include <boost/spirit/include/phoenix1_primitives.hpp> 19 #include <boost/spirit/include/phoenix1_tuples.hpp> 20 #include "fwd.hpp" 21 #include "iterator.hpp" 22 23 namespace quickbook 24 { 25 namespace cl = boost::spirit::classic; 26 27 /////////////////////////////////////////////////////////////////////////// 28 // 29 // scoped_parser<Impl> 30 // 31 // Impl is a struct with the methods: 32 // 33 // void start(); 34 // void success(parse_iterator, parse_iterator); 35 // void failure(); 36 // void cleanup(); 37 // 38 /////////////////////////////////////////////////////////////////////////// 39 40 template <typename Impl, typename Arguments, typename ParserT> 41 struct scoped_parser_impl 42 : public cl::unary< 43 ParserT, 44 cl::parser<scoped_parser_impl<Impl, Arguments, ParserT> > > 45 { 46 typedef scoped_parser_impl<Impl, Arguments, ParserT> self_t; 47 typedef cl::unary< 48 ParserT, 49 cl::parser<scoped_parser_impl<Impl, Arguments, ParserT> > > 50 base_t; 51 52 template <typename ScannerT> struct result 53 { 54 typedef cl::match<> type; 55 }; 56 scoped_parser_implquickbook::scoped_parser_impl57 scoped_parser_impl( 58 Impl const& impl, Arguments const& arguments, ParserT const& p) 59 : base_t(p), impl_(impl), arguments_(arguments) 60 { 61 } 62 63 struct scoped 64 { scopedquickbook::scoped_parser_impl::scoped65 explicit scoped(Impl const& impl) : impl_(impl), in_progress_(false) 66 { 67 } 68 69 typedef phoenix::tuple_index<0> t0; 70 typedef phoenix::tuple_index<1> t1; 71 startquickbook::scoped_parser_impl::scoped72 bool start(phoenix::tuple<> const&) 73 { 74 in_progress_ = impl_.start(); 75 return in_progress_; 76 } 77 startquickbook::scoped_parser_impl::scoped78 template <typename Arg1> bool start(phoenix::tuple<Arg1> const& x) 79 { 80 in_progress_ = 81 phoenix::bind(&Impl::start)(phoenix::var(impl_), x[t0()])(); 82 return in_progress_; 83 } 84 85 template <typename Arg1, typename Arg2> startquickbook::scoped_parser_impl::scoped86 bool start(phoenix::tuple<Arg1, Arg2> const& x) 87 { 88 in_progress_ = phoenix::bind(&Impl::start)( 89 phoenix::var(impl_), x[t0()], x[t1()])(); 90 return in_progress_; 91 } 92 successquickbook::scoped_parser_impl::scoped93 void success(parse_iterator f, parse_iterator l) 94 { 95 in_progress_ = false; 96 impl_.success(f, l); 97 } 98 failurequickbook::scoped_parser_impl::scoped99 void failure() 100 { 101 in_progress_ = false; 102 impl_.failure(); 103 } 104 ~scopedquickbook::scoped_parser_impl::scoped105 ~scoped() 106 { 107 if (in_progress_) impl_.failure(); 108 impl_.cleanup(); 109 } 110 111 Impl impl_; 112 bool in_progress_; 113 }; 114 115 template <typename ScannerT> parsequickbook::scoped_parser_impl116 typename result<ScannerT>::type parse(ScannerT const& scan) const 117 { 118 typedef typename ScannerT::iterator_t iterator_t; 119 iterator_t save = scan.first; 120 121 scoped scope(impl_); 122 if (!scope.start(arguments_)) return scan.no_match(); 123 124 typename cl::parser_result<ParserT, ScannerT>::type r = 125 this->subject().parse(scan); 126 127 bool success = scope.impl_.result(r, scan); 128 129 if (success) { 130 scope.success(save, scan.first); 131 132 if (r) { 133 return scan.create_match( 134 r.length(), cl::nil_t(), save, scan.first); 135 } 136 else { 137 return scan.create_match( 138 scan.first.base() - save.base(), cl::nil_t(), save, 139 scan.first); 140 } 141 } 142 else { 143 scope.failure(); 144 return scan.no_match(); 145 } 146 } 147 148 Impl impl_; 149 Arguments arguments_; 150 }; 151 152 template <typename Impl, typename Arguments> struct scoped_parser_gen 153 { scoped_parser_genquickbook::scoped_parser_gen154 explicit scoped_parser_gen(Impl impl, Arguments const& arguments) 155 : impl_(impl), arguments_(arguments) 156 { 157 } 158 159 template <typename ParserT> 160 scoped_parser_impl< 161 Impl, 162 Arguments, 163 typename cl::as_parser<ParserT>::type> operator []quickbook::scoped_parser_gen164 operator[](ParserT const& p) const 165 { 166 typedef cl::as_parser<ParserT> as_parser_t; 167 typedef typename as_parser_t::type parser_t; 168 169 return scoped_parser_impl<Impl, Arguments, parser_t>( 170 impl_, arguments_, p); 171 } 172 173 Impl impl_; 174 Arguments arguments_; 175 }; 176 177 template <typename Impl> struct scoped_parser 178 { scoped_parserquickbook::scoped_parser179 scoped_parser(Impl const& impl) : impl_(impl) {} 180 operator ()quickbook::scoped_parser181 scoped_parser_gen<Impl, phoenix::tuple<> > operator()() const 182 { 183 typedef phoenix::tuple<> tuple; 184 return scoped_parser_gen<Impl, tuple>(impl_, tuple()); 185 } 186 187 template <typename Arg1> operator ()quickbook::scoped_parser188 scoped_parser_gen<Impl, phoenix::tuple<Arg1> > operator()(Arg1 x1) const 189 { 190 typedef phoenix::tuple<Arg1> tuple; 191 return scoped_parser_gen<Impl, tuple>(impl_, tuple(x1)); 192 } 193 194 template <typename Arg1, typename Arg2> operator ()quickbook::scoped_parser195 scoped_parser_gen<Impl, phoenix::tuple<Arg1, Arg2> > operator()( 196 Arg1 x1, Arg2 x2) const 197 { 198 typedef phoenix::tuple<Arg1, Arg2> tuple; 199 return scoped_parser_gen<Impl, tuple>(impl_, tuple(x1, x2)); 200 } 201 202 Impl impl_; 203 204 private: 205 scoped_parser& operator=(scoped_parser const&); 206 }; 207 208 /////////////////////////////////////////////////////////////////////////// 209 // 210 // Lookback parser 211 // 212 // usage: lookback[body] 213 // 214 // Requires that iterator has typedef 'lookback_range' and function 215 // 'lookback' returning a 'lookback_range'. 216 // 217 /////////////////////////////////////////////////////////////////////////// 218 219 template <typename ParserT> 220 struct lookback_parser 221 : public cl::unary<ParserT, cl::parser<lookback_parser<ParserT> > > 222 { 223 typedef lookback_parser<ParserT> self_t; 224 typedef cl::unary<ParserT, cl::parser<lookback_parser<ParserT> > > 225 base_t; 226 227 template <typename ScannerT> struct result 228 { 229 typedef typename cl::parser_result<ParserT, ScannerT>::type type; 230 }; 231 lookback_parserquickbook::lookback_parser232 lookback_parser(ParserT const& p) : base_t(p) {} 233 234 template <typename ScannerT> parsequickbook::lookback_parser235 typename result<ScannerT>::type parse(ScannerT const& scan) const 236 { 237 typedef typename ScannerT::iterator_t::lookback_range::iterator 238 iterator_t; 239 typedef cl::scanner<iterator_t, typename ScannerT::policies_t> 240 scanner_t; 241 242 iterator_t begin = scan.first.lookback().begin(); 243 scanner_t lookback_scan(begin, scan.first.lookback().end(), scan); 244 245 if (this->subject().parse(lookback_scan)) 246 return scan.empty_match(); 247 else 248 return scan.no_match(); 249 } 250 }; 251 252 struct lookback_gen 253 { 254 template <typename ParserT> operator []quickbook::lookback_gen255 lookback_parser<ParserT> operator[](ParserT const& p) const 256 { 257 return lookback_parser<ParserT>(p); 258 } 259 }; 260 261 lookback_gen const lookback = lookback_gen(); 262 263 /////////////////////////////////////////////////////////////////////////// 264 // 265 // UTF-8 code point 266 // 267 // Very crude, it doesn't check that the code point is in any way valid. 268 // Just looks for the beginning of the next character. This is just for 269 // implementing some crude fixes, rather than full unicode support. I'm 270 // sure experts would be appalled. 271 // 272 /////////////////////////////////////////////////////////////////////////// 273 274 struct u8_codepoint_parser : public cl::parser<u8_codepoint_parser> 275 { 276 typedef u8_codepoint_parser self_t; 277 278 template <typename Scanner> struct result 279 { 280 typedef cl::match<> type; 281 }; 282 283 template <typename Scanner> parsequickbook::u8_codepoint_parser284 typename result<Scanner>::type parse(Scanner const& scan) const 285 { 286 typedef typename Scanner::iterator_t iterator_t; 287 288 if (scan.at_end()) return scan.no_match(); 289 290 iterator_t save(scan.first); 291 292 do { 293 ++scan.first; 294 } while (!scan.at_end() && 295 ((unsigned char)*scan.first & 0xc0) == 0x80); 296 297 return scan.create_match( 298 scan.first.base() - save.base(), cl::nil_t(), save, scan.first); 299 } 300 }; 301 302 u8_codepoint_parser const u8_codepoint_p = u8_codepoint_parser(); 303 } 304 305 #endif // BOOST_QUICKBOOK_SCOPED_BLOCK_HPP 306