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