LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
tokens.h
Go to the documentation of this file.
1 #ifndef fhiclcpp_tokens_h
2 #define fhiclcpp_tokens_h
3 
4 // ======================================================================
5 //
6 // tokens
7 //
8 // ======================================================================
9 
10 #include "boost/spirit/home/support/terminal.hpp"
11 #include "boost/spirit/include/qi.hpp"
12 #include "cetlib/canonical_number.h"
15 
16 #include <cctype>
17 #include <cstddef>
18 #include <string>
19 
20 namespace qi = boost::spirit::qi;
21 
22 // ----------------------------------------------------------------------
23 // utilities:
24 
25 namespace fhicl {
26 
27  inline bool
28  maximally_munched(char const ch)
29  {
30  return !std::isgraph(ch) || ch == '#' || ch == '/' || ch == ',' ||
31  ch == ']' || ch == '}';
32  }
33 
34  inline bool
35  maximally_munched_number(char const ch)
36  {
37  return maximally_munched(ch) || ch == ')';
38  }
39 
40  inline bool
41  maximally_munched_ass(char const ch)
42  {
43  return maximally_munched(ch) || ch == '.' || ch == '[' || ch == ':';
44  }
45 
46  inline bool
47  maximally_munched_dss(char const ch)
48  {
49  return maximally_munched(ch);
50  }
51 
52 } // fhicl
53 
54 // ----------------------------------------------------------------------
55 // identify custom terminal symbols:
56 
57 namespace fhicl {
58  BOOST_SPIRIT_TERMINAL(real)
59  BOOST_SPIRIT_TERMINAL(uint)
60  BOOST_SPIRIT_TERMINAL(hex)
61  BOOST_SPIRIT_TERMINAL(bin)
62  BOOST_SPIRIT_TERMINAL(ass)
63  BOOST_SPIRIT_TERMINAL(dss)
64  BOOST_SPIRIT_TERMINAL(dbid)
65  BOOST_SPIRIT_TERMINAL(binding)
66 }
67 
68 // ----------------------------------------------------------------------
69 // identify our tokens as terminals and in qi::domain (only for parsing):
70 
71 namespace boost {
72  namespace spirit {
73 
74  template <>
75  struct use_terminal<qi::domain, fhicl::tag::real> : mpl::true_ {
76  };
77 
78  template <>
79  struct use_terminal<qi::domain, fhicl::tag::uint> : mpl::true_ {
80  };
81 
82  template <>
83  struct use_terminal<qi::domain, fhicl::tag::hex> : mpl::true_ {
84  };
85 
86  template <>
87  struct use_terminal<qi::domain, fhicl::tag::dbid> : mpl::true_ {
88  };
89 
90  template <>
91  struct use_terminal<qi::domain, fhicl::tag::bin> : mpl::true_ {
92  };
93 
94  template <>
95  struct use_terminal<qi::domain, fhicl::tag::ass> : mpl::true_ {
96  };
97 
98  template <>
99  struct use_terminal<qi::domain, fhicl::tag::dss> : mpl::true_ {
100  };
101 
102  template <>
103  struct use_terminal<qi::domain, fhicl::tag::binding> : mpl::true_ {
104  };
105  }
106 } // boost::spirit
107 
108 // ----------------------------------------------------------------------
109 // implement each token parser:
110 
111 namespace fhicl {
112 
113  struct real_parser : qi::primitive_parser<real_parser> {
114  // designate type resulting from successful parse:
115  template <typename Context, typename Iterator>
116  struct attribute {
117  using type = std::string;
118  };
119 
120  // do the parse:
121  template <typename Iterator,
122  typename Context,
123  typename Skipper,
124  typename Attribute>
125  bool
126  parse(Iterator& first,
127  Iterator const& last,
128  Context&,
129  Skipper const& skipper,
130  Attribute& attr) const
131  {
132  boost::spirit::qi::skip_over(first, last, skipper);
133 
134  static std::string const allowed{"0123456789.-+eE"};
135  Iterator it = first;
136  while (it != last && allowed.find(*it) != std::string::npos)
137  ++it;
138 
139  if (it != last && !maximally_munched_number(*it))
140  return false;
141 
142  Attribute raw(first, it);
143  if (raw.empty())
144  return false;
145 
146  Attribute result;
147  if (!cet::canonical_number(raw, result))
148  return false;
149 
150  first = it;
151  boost::spirit::traits::assign_to(result, attr);
152  return true;
153  }
154 
155  // identify this token (in case of error):
156  template <typename Context>
157  boost::spirit::info
158  what(Context& /*unused */) const
159  {
160  return boost::spirit::info{"fhicl::real"};
161  }
162 
163  }; // real_parser
164 
165  struct uint_parser : boost::spirit::qi::primitive_parser<uint_parser> {
166  // designate type resulting from successful parse:
167  template <typename Context, typename Iterator>
168  struct attribute {
169  using type = std::string;
170  };
171 
172  // do the parse:
173  template <typename Iterator,
174  typename Context,
175  typename Skipper,
176  typename Attribute>
177  bool
178  parse(Iterator& first,
179  Iterator const& last,
180  Context&,
181  Skipper const& skipper,
182  Attribute& attr) const
183  {
184  boost::spirit::qi::skip_over(first, last, skipper);
185 
186  Iterator it = first;
187  while (it != last && std::isdigit(*it))
188  ++it;
189  Attribute result(first, it);
190 
191  if (result.empty())
192  return false;
193 
194  if (it != last && !maximally_munched_number(*it))
195  return false;
196 
197  for (std::size_t ndig = result.size(); ndig > 1 && result[0] == '0';
198  --ndig)
199  result.erase(0, 1);
200 
201  first = it;
202  boost::spirit::traits::assign_to(result, attr);
203  return true;
204  }
205 
206  // identify this token (in case of error):
207  template <typename Context>
208  boost::spirit::info
209  what(Context& /*unused */) const
210  {
211  return boost::spirit::info{"fhicl::uint"};
212  }
213 
214  }; // uint_parser
215 
216  struct hex_parser : qi::primitive_parser<hex_parser> {
217  // designate type resulting from successful parse:
218  template <typename Context, typename Iterator>
219  struct attribute {
220  using type = std::string;
221  };
222 
223  // do the parse:
224  template <typename Iterator,
225  typename Context,
226  typename Skipper,
227  typename Attribute>
228  bool
229  parse(Iterator& first,
230  Iterator const& last,
231  Context&,
232  Skipper const& skipper,
233  Attribute& attr) const
234  {
235  boost::spirit::qi::skip_over(first, last, skipper);
236 
237  static std::string const allowed{"0123456789abcdefABCDEF"};
238  Iterator it = first;
239 
240  if (it == last || *it != '0')
241  return false;
242 
243  ++it;
244 
245  if (it == last || toupper(*it) != 'X')
246  return false;
247 
248  ++it;
249 
250  while (it != last && allowed.find(*it) != std::string::npos)
251  ++it;
252 
253  if (it != last && !maximally_munched_number(*it))
254  return false;
255 
256  Attribute raw(first, it);
257  if (raw.empty() || raw.size() == 2)
258  return false;
259 
260  Attribute result;
261  if (!cet::canonical_number(raw, result))
262  return false;
263 
264  first = it;
265  boost::spirit::traits::assign_to(result, attr);
266  return true;
267  }
268 
269  // identify this token (in case of error):
270  template <typename Context>
271  boost::spirit::info
272  what(Context& /*unused */) const
273  {
274  return boost::spirit::info{"fhicl::hex"};
275  }
276 
277  }; // hex_parser
278 
279  struct dbid_parser : qi::primitive_parser<dbid_parser> {
280  // designate type resulting from successful parse:
281  template <typename Context, typename Iterator>
282  struct attribute {
283  using type = std::string;
284  };
285 
286  // do the parse:
287  template <typename Iterator,
288  typename Context,
289  typename Skipper,
290  typename Attribute>
291  bool
292  parse(Iterator& first,
293  Iterator const& last,
294  Context&,
295  Skipper const& skipper,
296  Attribute& attr) const
297  {
298  boost::spirit::qi::skip_over(first, last, skipper);
299 
300  static std::string const allowed{"0123456789abcdefABCDEF"};
301  Iterator it = first;
302 
303  if (it == last)
304  return false;
305 
306  while (it != last && allowed.find(*it) != std::string::npos)
307  ++it;
308 
309  if (it != last && !maximally_munched_number(*it))
310  return false;
311 
312  Attribute result(first, it);
313  if (result.size() != ParameterSetID::max_str_size())
314  return false;
315 
316  first = it;
317  boost::spirit::traits::assign_to(result, attr);
318  return true;
319  }
320 
321  // identify this token (in case of error):
322  template <typename Context>
323  boost::spirit::info
324  what(Context& /*unused */) const
325  {
326  return boost::spirit::info{"fhicl::dbid"};
327  }
328 
329  }; // dbid_parser
330 
331  struct bin_parser : qi::primitive_parser<bin_parser> {
332  // designate type resulting from successful parse:
333  template <typename Context, typename Iterator>
334  struct attribute {
335  using type = std::string;
336  };
337 
338  // do the parse:
339  template <typename Iterator,
340  typename Context,
341  typename Skipper,
342  typename Attribute>
343  bool
344  parse(Iterator& first,
345  Iterator const& last,
346  Context&,
347  Skipper const& skipper,
348  Attribute& attr) const
349  {
350  boost::spirit::qi::skip_over(first, last, skipper);
351 
352  static std::string const allowed{"01"};
353  Iterator it = first;
354 
355  if (it == last || *it != '0')
356  return false;
357 
358  ++it;
359 
360  if (it == last || toupper(*it) != 'B')
361  return false;
362 
363  ++it;
364 
365  while (it != last && allowed.find(*it) != std::string::npos)
366  ++it;
367 
368  if (it != last && !maximally_munched_number(*it))
369  return false;
370 
371  Attribute raw(first, it);
372  if (raw.empty() || raw.size() == 2)
373  return false;
374 
375  Attribute result;
376  if (!cet::canonical_number(raw, result))
377  return false;
378 
379  first = it;
380  boost::spirit::traits::assign_to(result, attr);
381  return true;
382  }
383 
384  // identify this token (in case of error):
385  template <typename Context>
386  boost::spirit::info
387  what(Context& /*unused */) const
388  {
389  return boost::spirit::info{"fhicl::bin"};
390  }
391 
392  }; // bin_parser
393 
394  struct ass_parser : qi::primitive_parser<ass_parser> {
395  // designate type resulting from successful parse:
396  template <typename Context, typename Iterator>
397  struct attribute {
398  using type = std::string;
399  };
400 
401  // do the parse:
402  template <typename Iterator,
403  typename Context,
404  typename Skipper,
405  typename Attribute>
406  bool
407  parse(Iterator& first,
408  Iterator const& last,
409  Context&,
410  Skipper const& skipper,
411  Attribute& attr) const
412  {
413  boost::spirit::qi::skip_over(first, last, skipper);
414 
415  Iterator it = first;
416  while (it != last && (std::isalnum(*it) || *it == '_'))
417  ++it;
418 
419  if (it != last && !maximally_munched_ass(*it))
420  return false;
421 
422  Attribute result(first, it);
423  if (result.empty() || std::isdigit(result[0]))
424  return false;
425 
426  first = it;
427  boost::spirit::traits::assign_to(result, attr);
428  return true;
429  }
430 
431  // identify this token (in case of error):
432  template <typename Context>
433  boost::spirit::info
434  what(Context& /*unused */) const
435  {
436  return boost::spirit::info{"fhicl::ass"};
437  }
438 
439  }; // ass_parser
440 
441  struct dss_parser : qi::primitive_parser<dss_parser> {
442  // designate type resulting from successful parse:
443  template <typename Context, typename Iterator>
444  struct attribute {
445  using type = std::string;
446  };
447 
448  // do the parse:
449  template <typename Iterator,
450  typename Context,
451  typename Skipper,
452  typename Attribute>
453  bool
454  parse(Iterator& first,
455  Iterator const& last,
456  Context&,
457  Skipper const& skipper,
458  Attribute& attr) const
459  {
460  boost::spirit::qi::skip_over(first, last, skipper);
461 
462  bool all_digits = true;
463  Iterator it = first;
464  for (; it != last && (std::isalnum(*it) || *it == '_'); ++it)
465  all_digits = all_digits && std::isdigit(*it);
466 
467  if (it != last && !maximally_munched_dss(*it))
468  return false;
469 
470  Attribute result(first, it);
471  if (result.empty() || all_digits || !std::isdigit(result[0]))
472  return false;
473 
474  first = it;
475  boost::spirit::traits::assign_to(result, attr);
476  return true;
477  }
478 
479  // identify this token (in case of error):
480  template <typename Context>
481  boost::spirit::info
482  what(Context& /*unused */) const
483  {
484  return boost::spirit::info{"fhicl::dss"};
485  }
486 
487  }; // dss_parser
488 
489  struct binding_parser : qi::primitive_parser<binding_parser> {
490  // Desired type resulting from a successful parse:
491  template <typename Context, typename Iterator>
492  struct attribute {
494  };
495 
496  // Do the parse:
497  template <typename Iterator,
498  typename Context,
499  typename Skipper,
500  typename Attribute>
501  bool
502  parse(Iterator& first,
503  Iterator const& last,
504  Context& c,
505  Skipper const& skipper,
506  Attribute& attr) const
507  {
509  boost::spirit::qi::skip_over(first, last, skipper);
510 
511  Attribute result = binding_modifier::NONE;
512  boost::spirit::qi::symbols<char, binding_modifier> modifiers;
513  modifiers.add("@protect_ignore", binding_modifier::PROTECT_IGNORE);
514  modifiers.add("@protect_error", binding_modifier::PROTECT_ERROR);
515 #if 0 /* Preparation for issue #7231. */
516  modifiers.add("@initial", binding_modifier::INITIAL);
517  modifiers.add("@replace", binding_modifier::REPLACE);
518  modifiers.add("@replace_compat", binding_modifier::REPLACE_COMPAT);
519  modifiers.add("@add_or_replace_compat", binding_modifier::ADD_OR_REPLACE_COMPAT);
520 #endif
521  if (((*first) == ':') ||
522  (modifiers.parse(first, last, c, skipper, result) &&
523  (*first) == ':')) {
524  ++first;
525  } else {
526  return false;
527  }
528  boost::spirit::traits::assign_to(result, attr);
529  return true;
530  }
531 
532  // identify this token (in case of error):
533  template <typename Context>
534  boost::spirit::info
535  what(Context&) const
536  {
537  return boost::spirit::info{"fhicl::binding"};
538  }
539  }; // binding_parser.
540 
541 } // fhicl
542 
543 // ----------------------------------------------------------------------
544 // provide factory functions to create instances of our parser:
545 
546 namespace boost {
547  namespace spirit {
548  namespace qi {
549 
550  template <typename Modifiers>
551  struct make_primitive<fhicl::tag::real, Modifiers> {
553 
554  result_type operator()(unused_type, unused_type) const
555  {
556  return result_type{};
557  }
558 
559  }; // make_primitive<...real...>
560 
561  template <typename Modifiers>
562  struct make_primitive<fhicl::tag::uint, Modifiers> {
564 
565  result_type operator()(unused_type, unused_type) const
566  {
567  return result_type{};
568  }
569 
570  }; // make_primitive<...uint...>
571 
572  template <typename Modifiers>
573  struct make_primitive<fhicl::tag::hex, Modifiers> {
575 
576  result_type operator()(unused_type, unused_type) const
577  {
578  return result_type{};
579  }
580 
581  }; // make_primitive<...hex...>
582 
583  template <typename Modifiers>
584  struct make_primitive<fhicl::tag::dbid, Modifiers> {
586 
587  result_type operator()(unused_type, unused_type) const
588  {
589  return result_type{};
590  }
591 
592  }; // make_primitive<...dbid...>
593 
594  template <typename Modifiers>
595  struct make_primitive<fhicl::tag::bin, Modifiers> {
597 
598  result_type operator()(unused_type, unused_type) const
599  {
600  return result_type{};
601  }
602 
603  }; // make_primitive<...bin...>
604 
605  template <typename Modifiers>
606  struct make_primitive<fhicl::tag::ass, Modifiers> {
608 
609  result_type operator()(unused_type, unused_type) const
610  {
611  return result_type{};
612  }
613 
614  }; // make_primitive<...ass...>
615 
616  template <typename Modifiers>
617  struct make_primitive<fhicl::tag::dss, Modifiers> {
619 
620  result_type operator()(unused_type, unused_type) const
621  {
622  return result_type{};
623  }
624 
625  }; // make_primitive<...dss...>
626 
627  template <typename Modifiers>
628  struct make_primitive<fhicl::tag::binding, Modifiers> {
630 
631  result_type operator()(unused_type, unused_type) const
632  {
633  return result_type{};
634  }
635 
636  }; // make_primitive<...binding...>
637  }
638  }
639 } // boost::spirit::qi
640 
641  // ======================================================================
642 
643 #endif /* fhiclcpp_tokens_h */
644 
645 // Local Variables:
646 // mode: c++
647 // End:
result_type operator()(unused_type, unused_type) const
Definition: tokens.h:620
bool parse(Iterator &first, Iterator const &last, Context &c, Skipper const &skipper, Attribute &attr) const
Definition: tokens.h:502
result_type operator()(unused_type, unused_type) const
Definition: tokens.h:554
Raw data description.
Definition: RawTypes.h:6
bool maximally_munched(char const ch)
Definition: tokens.h:28
bool parse(Iterator &first, Iterator const &last, Context &, Skipper const &skipper, Attribute &attr) const
Definition: tokens.h:178
boost::spirit::info what(Context &) const
Definition: tokens.h:272
boost::spirit::info what(Context &) const
Definition: tokens.h:324
bool parse(Iterator &first, Iterator const &last, Context &, Skipper const &skipper, Attribute &attr) const
Definition: tokens.h:407
parameter set interface
static std::size_t max_str_size()
result_type operator()(unused_type, unused_type) const
Definition: tokens.h:565
bool maximally_munched_dss(char const ch)
Definition: tokens.h:47
bool parse(Iterator &first, Iterator const &last, Context &, Skipper const &skipper, Attribute &attr) const
Definition: tokens.h:126
float bin[41]
Definition: plottest35.C:14
bool parse(Iterator &first, Iterator const &last, Context &, Skipper const &skipper, Attribute &attr) const
Definition: tokens.h:344
boost::spirit::info what(Context &) const
Definition: tokens.h:535
bool parse(Iterator &first, Iterator const &last, Context &, Skipper const &skipper, Attribute &attr) const
Definition: tokens.h:292
result_type operator()(unused_type, unused_type) const
Definition: tokens.h:587
boost::spirit::info what(Context &) const
Definition: tokens.h:209
boost::spirit::info what(Context &) const
Definition: tokens.h:158
result_type operator()(unused_type, unused_type) const
Definition: tokens.h:631
boost::spirit::info what(Context &) const
Definition: tokens.h:387
bool parse(Iterator &first, Iterator const &last, Context &, Skipper const &skipper, Attribute &attr) const
Definition: tokens.h:454
bool maximally_munched_number(char const ch)
Definition: tokens.h:35
bool parse(Iterator &first, Iterator const &last, Context &, Skipper const &skipper, Attribute &attr) const
Definition: tokens.h:229
result_type operator()(unused_type, unused_type) const
Definition: tokens.h:598
result_type operator()(unused_type, unused_type) const
Definition: tokens.h:609
boost::spirit::info what(Context &) const
Definition: tokens.h:482
boost::spirit::info what(Context &) const
Definition: tokens.h:434
bool maximally_munched_ass(char const ch)
Definition: tokens.h:41
result_type operator()(unused_type, unused_type) const
Definition: tokens.h:576