1 /*============================================================================= 2 Copyright (c) 2002-2003 Hartmut Kaiser 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_LISTS_HPP 9 #define BOOST_SPIRIT_LISTS_HPP 10 11 /////////////////////////////////////////////////////////////////////////////// 12 #include <boost/config.hpp> 13 #include <boost/spirit/home/classic/namespace.hpp> 14 #include <boost/spirit/home/classic/meta/as_parser.hpp> 15 #include <boost/spirit/home/classic/core/parser.hpp> 16 #include <boost/spirit/home/classic/core/composite/composite.hpp> 17 18 #include <boost/spirit/home/classic/utility/lists_fwd.hpp> 19 #include <boost/spirit/home/classic/utility/impl/lists.ipp> 20 21 /////////////////////////////////////////////////////////////////////////////// 22 namespace boost { namespace spirit { 23 24 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN 25 26 /////////////////////////////////////////////////////////////////////////////// 27 // 28 // list_parser class 29 // 30 // List parsers allow to parse constructs like 31 // 32 // item >> *(delim >> item) 33 // 34 // where 'item' is an auxiliary expression to parse and 'delim' is an 35 // auxiliary delimiter to parse. 36 // 37 // The list_parser class also can match an optional closing delimiter 38 // represented by the 'end' parser at the end of the list: 39 // 40 // item >> *(delim >> item) >> !end. 41 // 42 // If ItemT is an action_parser_category type (parser with an attached 43 // semantic action) we have to do something special. This happens, if the 44 // user wrote something like: 45 // 46 // list_p(item[f], delim) 47 // 48 // where 'item' is the parser matching one item of the list sequence and 49 // 'f' is a functor to be called after matching one item. If we would do 50 // nothing, the resulting code would parse the sequence as follows: 51 // 52 // (item[f] - delim) >> *(delim >> (item[f] - delim)) 53 // 54 // what in most cases is not what the user expects. 55 // (If this _is_ what you've expected, then please use one of the list_p 56 // generator functions 'direct()', which will inhibit re-attaching 57 // the actor to the item parser). 58 // 59 // To make the list parser behave as expected: 60 // 61 // (item - delim)[f] >> *(delim >> (item - delim)[f]) 62 // 63 // the actor attached to the 'item' parser has to be re-attached to the 64 // *(item - delim) parser construct, which will make the resulting list 65 // parser 'do the right thing'. 66 // 67 // Additionally special care must be taken, if the item parser is a 68 // unary_parser_category type parser as 69 // 70 // list_p(*anychar_p, ',') 71 // 72 // which without any refactoring would result in 73 // 74 // (*anychar_p - ch_p(',')) 75 // >> *( ch_p(',') >> (*anychar_p - ch_p(',')) ) 76 // 77 // and will not give the expected result (the first *anychar_p will eat up 78 // all the input up to the end of the input stream). So we have to 79 // refactor this into: 80 // 81 // *(anychar_p - ch_p(',')) 82 // >> *( ch_p(',') >> *(anychar_p - ch_p(',')) ) 83 // 84 // what will give the correct result. 85 // 86 // The case, where the item parser is a combination of the two mentioned 87 // problems (i.e. the item parser is a unary parser with an attached 88 // action), is handled accordingly too: 89 // 90 // list_p((*anychar_p)[f], ',') 91 // 92 // will be parsed as expected: 93 // 94 // (*(anychar_p - ch_p(',')))[f] 95 // >> *( ch_p(',') >> (*(anychar_p - ch_p(',')))[f] ). 96 // 97 /////////////////////////////////////////////////////////////////////////////// 98 template < 99 typename ItemT, typename DelimT, typename EndT, typename CategoryT 100 > 101 struct list_parser : 102 public parser<list_parser<ItemT, DelimT, EndT, CategoryT> > { 103 104 typedef list_parser<ItemT, DelimT, EndT, CategoryT> self_t; 105 typedef CategoryT parser_category_t; 106 list_parserboost::spirit::list_parser107 list_parser(ItemT const &item_, DelimT const &delim_, 108 EndT const& end_ = no_list_endtoken()) 109 : item(item_), delim(delim_), end(end_) 110 {} 111 112 template <typename ScannerT> 113 typename parser_result<self_t, ScannerT>::type parseboost::spirit::list_parser114 parse(ScannerT const& scan) const 115 { 116 return impl::list_parser_type<CategoryT> 117 ::parse(scan, *this, item, delim, end); 118 } 119 120 private: 121 typename as_parser<ItemT>::type::embed_t item; 122 typename as_parser<DelimT>::type::embed_t delim; 123 typename as_parser<EndT>::type::embed_t end; 124 }; 125 126 /////////////////////////////////////////////////////////////////////////////// 127 // 128 // List parser generator template 129 // 130 // This is a helper for generating a correct list_parser<> from 131 // auxiliary parameters. There are the following types supported as 132 // parameters yet: parsers, single characters and strings (see 133 // as_parser<> in meta/as_parser.hpp). 134 // 135 // The list_parser_gen by itself can be used for parsing comma separated 136 // lists without item formatting: 137 // 138 // list_p.parse(...) 139 // matches any comma separated list. 140 // 141 // If list_p is used with one parameter, this parameter is used to match 142 // the delimiter: 143 // 144 // list_p(';').parse(...) 145 // matches any semicolon separated list. 146 // 147 // If list_p is used with two parameters, the first parameter is used to 148 // match the items and the second parameter matches the delimiters: 149 // 150 // list_p(uint_p, ',').parse(...) 151 // matches comma separated unsigned integers. 152 // 153 // If list_p is used with three parameters, the first parameter is used 154 // to match the items, the second one is used to match the delimiters and 155 // the third one is used to match an optional ending token sequence: 156 // 157 // list_p(real_p, ';', eol_p).parse(...) 158 // matches a semicolon separated list of real numbers optionally 159 // followed by an end of line. 160 // 161 // The list_p in the previous examples denotes the predefined parser 162 // generator, which should be used to define list parsers (see below). 163 // 164 /////////////////////////////////////////////////////////////////////////////// 165 166 template <typename CharT = char> 167 struct list_parser_gen : 168 public list_parser<kleene_star<anychar_parser>, chlit<CharT> > 169 { 170 typedef list_parser_gen<CharT> self_t; 171 172 // construct the list_parser_gen object as an list parser for comma separated 173 // lists without item formatting. list_parser_genboost::spirit::list_parser_gen174 list_parser_gen() 175 : list_parser<kleene_star<anychar_parser>, chlit<CharT> > 176 (*anychar_p, chlit<CharT>(',')) 177 {} 178 179 // The following generator functions should be used under normal circumstances. 180 // (the operator()(...) functions) 181 182 // Generic generator functions for creation of concrete list parsers, which 183 // support 'normal' syntax: 184 // 185 // item >> *(delim >> item) 186 // 187 // If item isn't given, everything between two delimiters is matched. 188 189 template<typename DelimT> 190 list_parser< 191 kleene_star<anychar_parser>, 192 typename as_parser<DelimT>::type, 193 no_list_endtoken, 194 unary_parser_category // there is no action to re-attach 195 > operator ()boost::spirit::list_parser_gen196 operator()(DelimT const &delim_) const 197 { 198 typedef kleene_star<anychar_parser> item_t; 199 typedef typename as_parser<DelimT>::type delim_t; 200 201 typedef 202 list_parser<item_t, delim_t, no_list_endtoken, unary_parser_category> 203 return_t; 204 205 return return_t(*anychar_p, as_parser<DelimT>::convert(delim_)); 206 } 207 208 template<typename ItemT, typename DelimT> 209 list_parser< 210 typename as_parser<ItemT>::type, 211 typename as_parser<DelimT>::type, 212 no_list_endtoken, 213 typename as_parser<ItemT>::type::parser_category_t 214 > operator ()boost::spirit::list_parser_gen215 operator()(ItemT const &item_, DelimT const &delim_) const 216 { 217 typedef typename as_parser<ItemT>::type item_t; 218 typedef typename as_parser<DelimT>::type delim_t; 219 typedef list_parser<item_t, delim_t, no_list_endtoken, 220 BOOST_DEDUCED_TYPENAME item_t::parser_category_t> 221 return_t; 222 223 return return_t( 224 as_parser<ItemT>::convert(item_), 225 as_parser<DelimT>::convert(delim_) 226 ); 227 } 228 229 // Generic generator function for creation of concrete list parsers, which 230 // support 'extended' syntax: 231 // 232 // item >> *(delim >> item) >> !end 233 234 template<typename ItemT, typename DelimT, typename EndT> 235 list_parser< 236 typename as_parser<ItemT>::type, 237 typename as_parser<DelimT>::type, 238 typename as_parser<EndT>::type, 239 typename as_parser<ItemT>::type::parser_category_t 240 > operator ()boost::spirit::list_parser_gen241 operator()( 242 ItemT const &item_, DelimT const &delim_, EndT const &end_) const 243 { 244 typedef typename as_parser<ItemT>::type item_t; 245 typedef typename as_parser<DelimT>::type delim_t; 246 typedef typename as_parser<EndT>::type end_t; 247 248 typedef list_parser<item_t, delim_t, end_t, 249 BOOST_DEDUCED_TYPENAME item_t::parser_category_t> 250 return_t; 251 252 return return_t( 253 as_parser<ItemT>::convert(item_), 254 as_parser<DelimT>::convert(delim_), 255 as_parser<EndT>::convert(end_) 256 ); 257 } 258 259 // The following functions should be used, if the 'item' parser has an attached 260 // semantic action or is a unary_parser_category type parser and the structure 261 // of the resulting list parser should _not_ be refactored during parser 262 // construction (see comment above). 263 264 // Generic generator function for creation of concrete list parsers, which 265 // support 'normal' syntax: 266 // 267 // item >> *(delim >> item) 268 269 template<typename ItemT, typename DelimT> 270 list_parser< 271 typename as_parser<ItemT>::type, 272 typename as_parser<DelimT>::type, 273 no_list_endtoken, 274 plain_parser_category // inhibit action re-attachment 275 > directboost::spirit::list_parser_gen276 direct(ItemT const &item_, DelimT const &delim_) const 277 { 278 typedef typename as_parser<ItemT>::type item_t; 279 typedef typename as_parser<DelimT>::type delim_t; 280 typedef list_parser<item_t, delim_t, no_list_endtoken, 281 plain_parser_category> 282 return_t; 283 284 return return_t( 285 as_parser<ItemT>::convert(item_), 286 as_parser<DelimT>::convert(delim_) 287 ); 288 } 289 290 // Generic generator function for creation of concrete list parsers, which 291 // support 'extended' syntax: 292 // 293 // item >> *(delim >> item) >> !end 294 295 template<typename ItemT, typename DelimT, typename EndT> 296 list_parser< 297 typename as_parser<ItemT>::type, 298 typename as_parser<DelimT>::type, 299 typename as_parser<EndT>::type, 300 plain_parser_category // inhibit action re-attachment 301 > directboost::spirit::list_parser_gen302 direct( 303 ItemT const &item_, DelimT const &delim_, EndT const &end_) const 304 { 305 typedef typename as_parser<ItemT>::type item_t; 306 typedef typename as_parser<DelimT>::type delim_t; 307 typedef typename as_parser<EndT>::type end_t; 308 309 typedef 310 list_parser<item_t, delim_t, end_t, plain_parser_category> 311 return_t; 312 313 return return_t( 314 as_parser<ItemT>::convert(item_), 315 as_parser<DelimT>::convert(delim_), 316 as_parser<EndT>::convert(end_) 317 ); 318 } 319 }; 320 321 /////////////////////////////////////////////////////////////////////////////// 322 // 323 // Predefined list parser generator 324 // 325 // The list_p parser generator can be used 326 // - by itself for parsing comma separated lists without item formatting 327 // or 328 // - for generating list parsers with auxiliary parser parameters 329 // for the 'item', 'delim' and 'end' subsequences. 330 // (see comment above) 331 // 332 /////////////////////////////////////////////////////////////////////////////// 333 const list_parser_gen<> list_p = list_parser_gen<>(); 334 335 /////////////////////////////////////////////////////////////////////////////// 336 BOOST_SPIRIT_CLASSIC_NAMESPACE_END 337 338 }} // namespace BOOST_SPIRIT_CLASSIC_NS 339 340 #endif 341