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 #ifndef BOOST_SPIRIT_QI_DIRECTIVE_REPEAT_HPP 9 #define BOOST_SPIRIT_QI_DIRECTIVE_REPEAT_HPP 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 // silence MSVC warning C4512: assignment operator could not be generated 95 BOOST_DELETED_FUNCTION(exact_iterator& operator= (exact_iterator const&)) 96 }; 97 98 template <typename T> 99 struct finite_iterator // handles repeat(min, max)[p] 100 { finite_iteratorboost::spirit::qi::finite_iterator101 finite_iterator(T const min_, T const max_) 102 : min BOOST_PREVENT_MACRO_SUBSTITUTION (min_) 103 , max BOOST_PREVENT_MACRO_SUBSTITUTION (max_) {} 104 105 typedef T type; startboost::spirit::qi::finite_iterator106 T start() const { return 0; } got_maxboost::spirit::qi::finite_iterator107 bool got_max(T i) const { return i >= max; } got_minboost::spirit::qi::finite_iterator108 bool got_min(T i) const { return i >= min; } 109 110 T const min; 111 T const max; 112 113 // silence MSVC warning C4512: assignment operator could not be generated 114 BOOST_DELETED_FUNCTION(finite_iterator& operator= (finite_iterator const&)) 115 }; 116 117 template <typename T> 118 struct infinite_iterator // handles repeat(min, inf)[p] 119 { infinite_iteratorboost::spirit::qi::infinite_iterator120 infinite_iterator(T const min_) 121 : min BOOST_PREVENT_MACRO_SUBSTITUTION (min_) {} 122 123 typedef T type; startboost::spirit::qi::infinite_iterator124 T start() const { return 0; } got_maxboost::spirit::qi::infinite_iterator125 bool got_max(T /*i*/) const { return false; } got_minboost::spirit::qi::infinite_iterator126 bool got_min(T i) const { return i >= min; } 127 128 T const min; 129 130 // silence MSVC warning C4512: assignment operator could not be generated 131 BOOST_DELETED_FUNCTION(infinite_iterator& operator= (infinite_iterator const&)) 132 }; 133 134 template <typename Subject, typename LoopIter> 135 struct repeat_parser : unary_parser<repeat_parser<Subject, LoopIter> > 136 { 137 typedef Subject subject_type; 138 139 template <typename Context, typename Iterator> 140 struct attribute 141 { 142 // Build a std::vector from the subject's attribute. Note 143 // that build_std_vector may return unused_type if the 144 // subject's attribute is an unused_type. 145 typedef typename 146 traits::build_std_vector< 147 typename traits::attribute_of< 148 Subject, Context, Iterator>::type 149 >::type 150 type; 151 }; 152 repeat_parserboost::spirit::qi::repeat_parser153 repeat_parser(Subject const& subject_, LoopIter const& iter_) 154 : subject(subject_), iter(iter_) {} 155 156 template <typename F> parse_containerboost::spirit::qi::repeat_parser157 bool parse_container(F f) const 158 { 159 typename LoopIter::type i = iter.start(); 160 for (/**/; !iter.got_min(i); ++i) 161 { 162 if (f (subject)) 163 return false; 164 } 165 166 // parse some more up to the maximum specified 167 typename F::iterator_type save = f.f.first; 168 for (/**/; !iter.got_max(i); ++i) 169 { 170 if (f (subject)) 171 break; 172 save = f.f.first; 173 } 174 175 f.f.first = save; 176 return true; 177 } 178 179 template <typename Iterator, typename Context 180 , typename Skipper, typename Attribute> parseboost::spirit::qi::repeat_parser181 bool parse(Iterator& first, Iterator const& last 182 , Context& context, Skipper const& skipper 183 , Attribute& attr_) const 184 { 185 typedef detail::fail_function<Iterator, Context, Skipper> 186 fail_function; 187 188 // ensure the attribute is actually a container type 189 traits::make_container(attr_); 190 191 Iterator iter_local = first; 192 fail_function f(iter_local, last, context, skipper); 193 if (!parse_container(detail::make_pass_container(f, attr_))) 194 return false; 195 196 first = f.first; 197 return true; 198 } 199 200 template <typename Context> whatboost::spirit::qi::repeat_parser201 info what(Context& context) const 202 { 203 return info("repeat", subject.what(context)); 204 } 205 206 Subject subject; 207 LoopIter iter; 208 209 // silence MSVC warning C4512: assignment operator could not be generated 210 BOOST_DELETED_FUNCTION(repeat_parser& operator= (repeat_parser const&)) 211 }; 212 213 /////////////////////////////////////////////////////////////////////////// 214 // Parser generators: make_xxx function (objects) 215 /////////////////////////////////////////////////////////////////////////// 216 template <typename Subject, typename Modifiers> 217 struct make_directive<tag::repeat, Subject, Modifiers> 218 { 219 typedef kleene<Subject> result_type; operator ()boost::spirit::qi::make_directive220 result_type operator()(unused_type, Subject const& subject, unused_type) const 221 { 222 return result_type(subject); 223 } 224 }; 225 226 template <typename T, typename Subject, typename Modifiers> 227 struct make_directive< 228 terminal_ex<tag::repeat, fusion::vector1<T> >, Subject, Modifiers> 229 { 230 typedef exact_iterator<T> iterator_type; 231 typedef repeat_parser<Subject, iterator_type> result_type; 232 233 template <typename Terminal> operator ()boost::spirit::qi::make_directive234 result_type operator()( 235 Terminal const& term, Subject const& subject, unused_type) const 236 { 237 return result_type(subject, fusion::at_c<0>(term.args)); 238 } 239 }; 240 241 template <typename T, typename Subject, typename Modifiers> 242 struct make_directive< 243 terminal_ex<tag::repeat, fusion::vector2<T, T> >, Subject, Modifiers> 244 { 245 typedef finite_iterator<T> iterator_type; 246 typedef repeat_parser<Subject, iterator_type> result_type; 247 248 template <typename Terminal> operator ()boost::spirit::qi::make_directive249 result_type operator()( 250 Terminal const& term, Subject const& subject, unused_type) const 251 { 252 return result_type(subject, 253 iterator_type( 254 fusion::at_c<0>(term.args) 255 , fusion::at_c<1>(term.args) 256 ) 257 ); 258 } 259 }; 260 261 template <typename T, typename Subject, typename Modifiers> 262 struct make_directive< 263 terminal_ex<tag::repeat 264 , fusion::vector2<T, inf_type> >, Subject, Modifiers> 265 { 266 typedef infinite_iterator<T> iterator_type; 267 typedef repeat_parser<Subject, iterator_type> result_type; 268 269 template <typename Terminal> operator ()boost::spirit::qi::make_directive270 result_type operator()( 271 Terminal const& term, Subject const& subject, unused_type) const 272 { 273 return result_type(subject, fusion::at_c<0>(term.args)); 274 } 275 }; 276 }}} 277 278 namespace boost { namespace spirit { namespace traits 279 { 280 /////////////////////////////////////////////////////////////////////////// 281 template <typename Subject, typename LoopIter> 282 struct has_semantic_action<qi::repeat_parser<Subject, LoopIter> > 283 : unary_has_semantic_action<Subject> {}; 284 285 /////////////////////////////////////////////////////////////////////////// 286 template <typename Subject, typename LoopIter, typename Attribute 287 , typename Context, typename Iterator> 288 struct handles_container<qi::repeat_parser<Subject, LoopIter> 289 , Attribute, Context, Iterator> 290 : mpl::true_ {}; 291 }}} 292 293 #endif 294