1 // Copyright (c) 2011 Aaron Graham 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #if !defined(BOOST_SPIRIT_REPOSITORY_QI_ADVANCE_JAN_23_2011_1203PM) 7 #define BOOST_SPIRIT_REPOSITORY_QI_ADVANCE_JAN_23_2011_1203PM 8 9 #include <boost/spirit/home/support/terminal.hpp> 10 #include <boost/spirit/include/qi_parse.hpp> 11 12 /////////////////////////////////////////////////////////////////////////////// 13 // definition the place holder 14 namespace boost { namespace spirit { namespace repository { namespace qi 15 { 16 BOOST_SPIRIT_TERMINAL_EX(advance) 17 }}}} 18 19 /////////////////////////////////////////////////////////////////////////////// 20 // implementation the enabler 21 namespace boost { namespace spirit 22 { 23 template <typename A0> 24 struct use_terminal<qi::domain 25 , terminal_ex<repository::qi::tag::advance, fusion::vector1<A0> > > 26 : mpl::or_<is_integral<A0>, is_enum<A0> > 27 {}; 28 29 template <> 30 struct use_lazy_terminal<qi::domain, repository::qi::tag::advance, 1> 31 : mpl::true_ 32 {}; 33 }} 34 35 /////////////////////////////////////////////////////////////////////////////// 36 // implementation of the parser 37 namespace boost { namespace spirit { namespace repository { namespace qi 38 { 39 template <typename Int> 40 struct advance_parser 41 : boost::spirit::qi::primitive_parser< advance_parser<Int> > 42 { 43 // Define the attribute type exposed by this parser component 44 template <typename Context, typename Iterator> 45 struct attribute 46 { 47 typedef boost::spirit::unused_type type; 48 }; 49 advance_parserboost::spirit::repository::qi::advance_parser50 advance_parser(Int dist) 51 : dist(dist) 52 {} 53 54 // This function is called during the actual parsing process 55 template <typename Iterator, typename Context 56 , typename Skipper, typename Attribute> parseboost::spirit::repository::qi::advance_parser57 bool parse(Iterator& first, Iterator const& last 58 , Context&, Skipper&, Attribute&) const 59 { 60 // This series of checks is designed to fail parsing on negative 61 // values, without generating a "expression always evaluates true" 62 // warning on unsigned types. 63 if (dist == Int(0)) return true; 64 if (dist < Int(1)) return false; 65 66 typedef typename std::iterator_traits<Iterator>::iterator_category 67 iterator_category; 68 return advance(first, last, iterator_category()); 69 } 70 71 // This function is called during error handling to create 72 // a human readable string for the error context. 73 template <typename Context> whatboost::spirit::repository::qi::advance_parser74 boost::spirit::info what(Context&) const 75 { 76 return boost::spirit::info("advance"); 77 } 78 79 private: 80 // this is the general implementation used by most iterator categories 81 template <typename Iterator, typename IteratorCategory> advanceboost::spirit::repository::qi::advance_parser82 bool advance(Iterator& first, Iterator const& last 83 , IteratorCategory) const 84 { 85 Int n = dist; 86 Iterator i = first; 87 while (n) 88 { 89 if (i == last) return false; 90 ++i; 91 --n; 92 } 93 first = i; 94 return true; 95 } 96 97 // this is a specialization for random access iterators 98 template <typename Iterator> advanceboost::spirit::repository::qi::advance_parser99 bool advance(Iterator& first, Iterator const& last 100 , std::random_access_iterator_tag) const 101 { 102 Iterator const it = first + dist; 103 if (it > last) return false; 104 first = it; 105 return true; 106 } 107 108 Int const dist; 109 }; 110 }}}} 111 112 /////////////////////////////////////////////////////////////////////////////// 113 // instantiation of the parser 114 namespace boost { namespace spirit { namespace qi 115 { 116 template <typename Modifiers, typename A0> 117 struct make_primitive< 118 terminal_ex<repository::qi::tag::advance, fusion::vector1<A0> > 119 , Modifiers> 120 { 121 typedef repository::qi::advance_parser<A0> result_type; 122 123 template <typename Terminal> operator ()boost::spirit::qi::make_primitive124 result_type operator()(Terminal const& term, unused_type) const 125 { 126 return result_type(fusion::at_c<0>(term.args)); 127 } 128 }; 129 }}} 130 131 #endif 132