lists.hpp 12 KB

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