1 /*============================================================================= 2 Copyright (c) 2001-2011 Joel de Guzman 3 Copyright (c) 2001-2011 Hartmut Kaiser 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 #if !defined(SPIRIT_REPEAT_NOVEMBER_14_2008_1148AM) 9 #define SPIRIT_REPEAT_NOVEMBER_14_2008_1148AM 10 11 #if defined(_MSC_VER) 12 #pragma once 13 #endif 14 15 #include <boost/spirit/home/qi/meta_compiler.hpp> 16 #include <boost/spirit/home/qi/parser.hpp> 17 #include <boost/spirit/home/qi/auxiliary/lazy.hpp> 18 #include <boost/spirit/home/qi/operator/kleene.hpp> 19 #include <boost/spirit/home/support/container.hpp> 20 #include <boost/spirit/home/support/common_terminals.hpp> 21 #include <boost/spirit/home/qi/detail/attributes.hpp> 22 #include <boost/spirit/home/qi/detail/fail_function.hpp> 23 #include <boost/spirit/home/qi/detail/pass_container.hpp> 24 #include <boost/spirit/home/support/info.hpp> 25 #include <boost/spirit/home/support/has_semantic_action.hpp> 26 #include <boost/spirit/home/support/handles_container.hpp> 27 #include <boost/fusion/include/at.hpp> 28 #include <vector> 29 30 namespace boost { namespace spirit 31 { 32 /////////////////////////////////////////////////////////////////////////// 33 // Enablers 34 /////////////////////////////////////////////////////////////////////////// 35 template <> 36 struct use_directive<qi::domain, tag::repeat> // enables repeat[p] 37 : mpl::true_ {}; 38 39 template <typename T> 40 struct use_directive<qi::domain 41 , terminal_ex<tag::repeat // enables repeat(exact)[p] 42 , fusion::vector1<T> > 43 > : mpl::true_ {}; 44 45 template <typename T> 46 struct use_directive<qi::domain 47 , terminal_ex<tag::repeat // enables repeat(min, max)[p] 48 , fusion::vector2<T, T> > 49 > : mpl::true_ {}; 50 51 template <typename T> 52 struct use_directive<qi::domain 53 , terminal_ex<tag::repeat // enables repeat(min, inf)[p] 54 , fusion::vector2<T, inf_type> > 55 > : mpl::true_ {}; 56 57 template <> // enables *lazy* repeat(exact)[p] 58 struct use_lazy_directive< 59 qi::domain 60 , tag::repeat 61 , 1 // arity 62 > : mpl::true_ {}; 63 64 template <> // enables *lazy* repeat(min, max)[p] 65 struct use_lazy_directive< // and repeat(min, inf)[p] 66 qi::domain 67 , tag::repeat 68 , 2 // arity 69 > : mpl::true_ {}; 70 }} 71 72 namespace boost { namespace spirit { namespace qi 73 { 74 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 75 using spirit::repeat; 76 using spirit::inf; 77 #endif 78 using spirit::repeat_type; 79 using spirit::inf_type; 80 81 template <typename T> 82 struct exact_iterator // handles repeat(exact)[p] 83 { exact_iteratorboost::spirit::qi::exact_iterator84 exact_iterator(T const exact_) 85 : exact(exact_) {} 86 87 typedef T type; startboost::spirit::qi::exact_iterator88 T start() const { return 0; } got_maxboost::spirit::qi::exact_iterator89 bool got_max(T i) const { return i >= exact; } got_minboost::spirit::qi::exact_iterator90 bool got_min(T i) const { return i >= exact; } 91 92 T const exact; 93 94 private: 95 // silence MSVC warning C4512: assignment operator could not be generated 96 exact_iterator& operator= (exact_iterator const&); 97 }; 98 99 template <typename T> 100 struct finite_iterator // handles repeat(min, max)[p] 101 { finite_iteratorboost::spirit::qi::finite_iterator102 finite_iterator(T const min_, T const max_) 103 : min BOOST_PREVENT_MACRO_SUBSTITUTION (min_) 104 , max BOOST_PREVENT_MACRO_SUBSTITUTION (max_) {} 105 106 typedef T type; startboost::spirit::qi::finite_iterator107 T start() const { return 0; } got_maxboost::spirit::qi::finite_iterator108 bool got_max(T i) const { return i >= max; } got_minboost::spirit::qi::finite_iterator109 bool got_min(T i) const { return i >= min; } 110 111 T const min; 112 T const max; 113 114 private: 115 // silence MSVC warning C4512: assignment operator could not be generated 116 finite_iterator& operator= (finite_iterator const&); 117 }; 118 119 template <typename T> 120 struct infinite_iterator // handles repeat(min, inf)[p] 121 { infinite_iteratorboost::spirit::qi::infinite_iterator122 infinite_iterator(T const min_) 123 : min BOOST_PREVENT_MACRO_SUBSTITUTION (min_) {} 124 125 typedef T type; startboost::spirit::qi::infinite_iterator126 T start() const { return 0; } got_maxboost::spirit::qi::infinite_iterator127 bool got_max(T /*i*/) const { return false; } got_minboost::spirit::qi::infinite_iterator128 bool got_min(T i) const { return i >= min; } 129 130 T const min; 131 132 private: 133 // silence MSVC warning C4512: assignment operator could not be generated 134 infinite_iterator& operator= (infinite_iterator const&); 135 }; 136 137 template <typename Subject, typename LoopIter> 138 struct repeat_parser : unary_parser<repeat_parser<Subject, LoopIter> > 139 { 140 typedef Subject subject_type; 141 142 template <typename Context, typename Iterator> 143 struct attribute 144 { 145 // Build a std::vector from the subject's attribute. Note 146 // that build_std_vector may return unused_type if the 147 // subject's attribute is an unused_type. 148 typedef typename 149 traits::build_std_vector< 150 typename traits::attribute_of< 151 Subject, Context, Iterator>::type 152 >::type 153 type; 154 }; 155 repeat_parserboost::spirit::qi::repeat_parser156 repeat_parser(Subject const& subject_, LoopIter const& iter_) 157 : subject(subject_), iter(iter_) {} 158 159 template <typename F> parse_containerboost::spirit::qi::repeat_parser160 bool parse_container(F f) const 161 { 162 typename LoopIter::type i = iter.start(); 163 for (/**/; !iter.got_min(i); ++i) 164 { 165 if (f (subject)) 166 return false; 167 } 168 169 // parse some more up to the maximum specified 170 typename F::iterator_type save = f.f.first; 171 for (/**/; !iter.got_max(i); ++i) 172 { 173 if (f (subject)) 174 break; 175 save = f.f.first; 176 } 177 178 f.f.first = save; 179 return true; 180 } 181 182 template <typename Iterator, typename Context 183 , typename Skipper, typename Attribute> parseboost::spirit::qi::repeat_parser184 bool parse(Iterator& first, Iterator const& last 185 , Context& context, Skipper const& skipper 186 , Attribute& attr_) const 187 { 188 typedef detail::fail_function<Iterator, Context, Skipper> 189 fail_function; 190 191 // ensure the attribute is actually a container type 192 traits::make_container(attr_); 193 194 Iterator iter_local = first; 195 fail_function f(iter_local, last, context, skipper); 196 if (!parse_container(detail::make_pass_container(f, attr_))) 197 return false; 198 199 first = f.first; 200 return true; 201 } 202 203 template <typename Context> whatboost::spirit::qi::repeat_parser204 info what(Context& context) const 205 { 206 return info("repeat", subject.what(context)); 207 } 208 209 Subject subject; 210 LoopIter iter; 211 212 private: 213 // silence MSVC warning C4512: assignment operator could not be generated 214 repeat_parser& operator= (repeat_parser const&); 215 }; 216 217 /////////////////////////////////////////////////////////////////////////// 218 // Parser generators: make_xxx function (objects) 219 /////////////////////////////////////////////////////////////////////////// 220 template <typename Subject, typename Modifiers> 221 struct make_directive<tag::repeat, Subject, Modifiers> 222 { 223 typedef kleene<Subject> result_type; operator ()boost::spirit::qi::make_directive224 result_type operator()(unused_type, Subject const& subject, unused_type) const 225 { 226 return result_type(subject); 227 } 228 }; 229 230 template <typename T, typename Subject, typename Modifiers> 231 struct make_directive< 232 terminal_ex<tag::repeat, fusion::vector1<T> >, Subject, Modifiers> 233 { 234 typedef exact_iterator<T> iterator_type; 235 typedef repeat_parser<Subject, iterator_type> result_type; 236 237 template <typename Terminal> operator ()boost::spirit::qi::make_directive238 result_type operator()( 239 Terminal const& term, Subject const& subject, unused_type) const 240 { 241 return result_type(subject, fusion::at_c<0>(term.args)); 242 } 243 }; 244 245 template <typename T, typename Subject, typename Modifiers> 246 struct make_directive< 247 terminal_ex<tag::repeat, fusion::vector2<T, T> >, Subject, Modifiers> 248 { 249 typedef finite_iterator<T> iterator_type; 250 typedef repeat_parser<Subject, iterator_type> result_type; 251 252 template <typename Terminal> operator ()boost::spirit::qi::make_directive253 result_type operator()( 254 Terminal const& term, Subject const& subject, unused_type) const 255 { 256 return result_type(subject, 257 iterator_type( 258 fusion::at_c<0>(term.args) 259 , fusion::at_c<1>(term.args) 260 ) 261 ); 262 } 263 }; 264 265 template <typename T, typename Subject, typename Modifiers> 266 struct make_directive< 267 terminal_ex<tag::repeat 268 , fusion::vector2<T, inf_type> >, Subject, Modifiers> 269 { 270 typedef infinite_iterator<T> iterator_type; 271 typedef repeat_parser<Subject, iterator_type> result_type; 272 273 template <typename Terminal> operator ()boost::spirit::qi::make_directive274 result_type operator()( 275 Terminal const& term, Subject const& subject, unused_type) const 276 { 277 return result_type(subject, fusion::at_c<0>(term.args)); 278 } 279 }; 280 }}} 281 282 namespace boost { namespace spirit { namespace traits 283 { 284 /////////////////////////////////////////////////////////////////////////// 285 template <typename Subject, typename LoopIter> 286 struct has_semantic_action<qi::repeat_parser<Subject, LoopIter> > 287 : unary_has_semantic_action<Subject> {}; 288 289 /////////////////////////////////////////////////////////////////////////// 290 template <typename Subject, typename LoopIter, typename Attribute 291 , typename Context, typename Iterator> 292 struct handles_container<qi::repeat_parser<Subject, LoopIter> 293 , Attribute, Context, Iterator> 294 : mpl::true_ {}; 295 }}} 296 297 #endif 298