LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
parse.cc
Go to the documentation of this file.
1 // ======================================================================
2 //
3 // parse
4 //
5 // ======================================================================
6 
7 #include "fhiclcpp/parse.h"
8 #include "cetlib/compiler_macros.h"
9 
10 #include "boost/any.hpp"
11 #ifdef __ICC
12 #pragma warning(push, disable : 780)
13 #endif
14 #pragma GCC diagnostic push
15 #pragma GCC diagnostic ignored "-Wshadow"
16 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
17 #pragma GCC diagnostic ignored "-Wunused-parameter"
18 #include "boost/spirit/include/phoenix_bind.hpp"
19 #include "boost/spirit/include/phoenix_operator.hpp"
20 #include "boost/spirit/include/qi.hpp"
21 #include "boost/spirit/include/qi_no_skip.hpp"
22 #include "boost/spirit/include/support_istream_iterator.hpp"
23 #ifdef __clang__
24 #pragma clang diagnostic ignored "-Wpedantic"
25 #else
26 #pragma GCC diagnostic ignored "-Wpedantic"
27 #endif
28 #include "boost/spirit/repository/home/qi/primitive/iter_pos.hpp"
29 #pragma GCC diagnostic pop
30 #ifdef __ICC
31 #pragma warning(pop)
32 #endif
33 
34 #include "cetlib/canonical_number.h"
35 #include "cetlib/canonical_string.h"
36 #include "cetlib/include.h"
37 #include "cetlib/includer.h"
39 #include "fhiclcpp/exception.h"
42 #include "fhiclcpp/tokens.h"
43 
44 #include "fhiclcpp/parse_shims.h"
45 #include <algorithm>
46 #include <string>
47 #include <vector>
48 
49 namespace ascii = ::boost::spirit::ascii;
50 namespace phx = ::boost::phoenix;
51 namespace qi = ::boost::spirit::qi;
52 
53 using ascii::char_;
54 using ascii::digit;
55 using ascii::graph;
56 using ascii::space;
57 
58 using phx::ref;
59 
60 using boost::spirit::repository::qi::iter_pos;
61 using qi::_val;
62 using qi::eol;
63 using qi::lexeme;
64 using namespace shims; // using qi::lit; /*moved to parse_shims.h*/
65 using qi::no_skip;
66 using qi::raw;
67 using qi::skip;
68 
69 using namespace fhicl;
75 
76 using fhicl::SEQUENCE;
77 using fhicl::TABLE;
78 using fhicl::TABLEID;
79 
80 // ----------------------------------------------------------------------
81 
82 namespace {
83 
84  void
85  check_protection(Protection p, extended_value& v, std::string name = "")
86  {
87  using std::max;
88  if (v.protection == Protection::NONE) {
89  v.protection = p;
90  } else if (v.protection < p) {
92  << "Nested item " << name << " has protection "
93  << to_string(v.protection)
94  << ((!v.src_info.empty()) ?
95  (std::string(" on ") + v.pretty_src_info()) :
96  "")
97  << ", which is incompatible with an enclosing item's protection of "
98  << to_string(p) << "\n";
99  };
100  if (v.tag == fhicl::SEQUENCE) {
101  std::size_t count = 0;
102  using std::to_string;
103  for (auto& subv : sequence_t(v)) {
104  check_protection(
105  max(p, v.protection), subv, name + '[' + to_string(count) + ']');
106  }
107  } else if (v.tag == fhicl::TABLE) {
108  for (auto& kvp : table_t(v)) {
109  std::string sname(name);
110  if (!sname.empty()) {
111  sname.append(".");
112  }
113  sname.append(kvp.first);
114  check_protection(max(p, v.protection), kvp.second, std::move(sname));
115  }
116  }
117  }
118 
119  void
120  check_protection(extended_value& v, std::string const name = "")
121  {
122  if (v.is_a(fhicl::SEQUENCE) || v.is_a(fhicl::TABLE)) {
123  check_protection(v.protection, v, std::move(name));
124  }
125  }
126 
128  set_protection(std::string const& name, binding_modifier m, extended_value& v)
129  {
130  switch (m) {
131  case binding_modifier::NONE:
132  break;
133  case binding_modifier::PROTECT_IGNORE:
134  case binding_modifier::PROTECT_ERROR:
135  auto p = static_cast<Protection>(m);
136  v.protection = p;
137  check_protection(v, name);
138  break;
139  }
140  return v;
141  }
142 
143  std::string
144  canon_nil(std::string const&)
145  {
146  static std::string const canon_nil(9, '\0');
147  return canon_nil;
148  }
149 
150  std::string
151  canon_inf(std::string const& inf)
152  {
153  return inf[0] == 'i' ? ('+' + inf) : inf;
154  }
155 
156  std::string
157  canon_num(std::string const& num)
158  {
159  std::string result;
160  if (!cet::canonical_number(num, result)) {
161  result = "####";
162  }
163  return result;
164  }
165 
166  std::string
167  canon_str(std::string const& str)
168  {
169  std::string result;
170  if (!cet::canonical_string(str, result)) {
171  result = "oops";
172  }
173  return result;
174  }
175 
176  void
177  rebool(bool& b, bool value)
178  {
179  b = value;
180  }
181 
183  xvalue_vp(bool b, value_tag t, boost::any v)
184  {
185  return extended_value(b, t, v);
186  }
187 
188  template <typename FwdIter>
190  xvalue_dp(bool b,
191  value_tag t,
192  boost::any v,
193  FwdIter pos,
194  cet::includer const& s)
195  {
196  std::string const src_info = s.src_whereis(pos);
197  return extended_value(b, t, v, src_info);
198  }
199 
200  complex_t
201  cplx(atom_t const& c1, atom_t const& c2)
202  {
203  return std::make_pair(c1, c2);
204  }
205 
206  template <typename FwdIter>
208  local_lookup(std::string const& name,
209  intermediate_table const& tbl,
210  bool in_prolog,
211  FwdIter pos,
212  cet::includer const& s) try {
213  extended_value result = tbl.find(name);
214  result.set_prolog(in_prolog);
215  result.set_src_info(s.src_whereis(pos));
216  return result;
217  }
218  catch (fhicl::exception const& e) {
219  throw fhicl::exception(fhicl::error::parse_error, "Local lookup error", e)
220  << "at " << s.highlighted_whereis(pos) << "\n";
221  }
222 
223  template <typename FwdIter>
225  database_lookup(std::string const&,
226  intermediate_table const&,
227  bool,
228  FwdIter pos,
229  cet::includer const& s)
230  {
231  throw fhicl::exception(fhicl::error::unimplemented, "Database lookup error")
232  << "at " << s.highlighted_whereis(pos)
233  << "\nFHiCL-cpp database lookup not yet available.\n";
234  }
235 
236  template <typename FwdIter>
237  void
238  tbl_insert(std::string const& name,
240  extended_value& value,
242  FwdIter pos,
243  cet::includer const& s)
244  {
245  try {
246  set_protection(name, m, value);
247  t.insert(name, value);
248  }
249  catch (fhicl::exception& e) {
250  throw fhicl::exception(
251  fhicl::error::parse_error, "Error in assignment:", e)
252  << " at " << s.highlighted_whereis(pos) << '\n';
253  }
254  }
255 
256  template <typename FwdIter>
257  void
258  tbl_erase(std::string const& name,
260  bool in_prolog,
261  FwdIter pos,
262  cet::includer const& s)
263  {
264  try {
265  t.erase(name, in_prolog);
266  }
267  catch (fhicl::exception& e) {
268  throw fhicl::exception(
269  fhicl::error::parse_error, "Error in erase attempt:", e)
270  << " at " << s.highlighted_whereis(pos) << '\n';
271  }
272  }
273 
274  void
275  map_insert(std::string const& name,
277  extended_value& value,
278  table_t& t)
279  {
280  set_protection(name, m, value);
281  auto const i = t.find(name);
282  if (i != t.end()) {
283  auto existing_protection = i->second.protection;
284  if (value.protection > existing_protection) {
286  << "Inserting name " << name << " would increase protection from "
287  << to_string(existing_protection) << " to "
288  << to_string(value.protection) << "\n(previous definition on "
289  << i->second.pretty_src_info() << ")\n";
290  }
291  switch (i->second.protection) {
292  case Protection::NONE:
293  break;
294  case Protection::PROTECT_IGNORE:
295  // Do not overwrite protected binding.
296  return;
297  case Protection::PROTECT_ERROR:
299  << '"' << name << "\" is protected on "
300  << i->second.pretty_src_info() << '\n';
301  }
302  }
303  t[name] = value;
304  }
305 
306  template <typename FwdIter>
307  void
308  map_insert_loc(std::string const& name,
310  extended_value& value,
311  table_t& t,
312  FwdIter pos,
313  cet::includer const& s)
314  {
315  try {
316  map_insert(name, m, value, t);
317  }
318  catch (fhicl::exception& e) {
319  throw fhicl::exception(
320  fhicl::error::parse_error, "Error in assignment:", e)
321  << " at " << s.highlighted_whereis(pos) << '\n';
322  }
323  }
324 
325  template <typename FwdIter>
326  void
327  insert_table_in_table(std::string const& name,
328  intermediate_table& tbl,
329  bool in_prolog,
330  table_t& t,
331  FwdIter pos,
332  cet::includer const& s)
333  {
334  extended_value const& xval = local_lookup(name, tbl, false, pos, s);
335  if (!xval.is_a(fhicl::TABLE)) {
337  << "key \"" << name << "\" does not refer to a table at "
338  << s.highlighted_whereis(pos) << "\n";
339  }
340  auto const& incoming = boost::any_cast<table_t const&>(xval.value);
341  for (auto incoming_item = incoming.cbegin(), e = incoming.cend();
342  incoming_item != e;
343  ++incoming_item) {
344  auto& element = t[incoming_item->first];
345  if (!element.is_a(fhicl::UNKNOWN)) {
346  // Already exists.
347  auto incoming_protection = incoming_item->second.protection;
348  if (incoming_protection > element.protection) {
350  << "@table::" << name << ": inserting name " << incoming_item->first
351  << " would increase protection from "
352  << to_string(element.protection) << " to "
353  << to_string(incoming_protection) << "\n(previous definition on "
354  << element.pretty_src_info() << ")\n";
355  }
356  switch (element.protection) {
357  case Protection::NONE:
358  break;
359  case Protection::PROTECT_IGNORE:
360  continue;
361  case Protection::PROTECT_ERROR:
363  << "@table::" << name << ": inserting name "
364  << incoming_item->first
365  << "would violate protection on existing item"
366  << "\n(previous definition on " << element.pretty_src_info()
367  << ")\n";
368  }
369  }
370  element = incoming_item->second;
371  element.set_prolog(in_prolog);
372  element.set_src_info(s.src_whereis(pos));
373  }
374  }
375 
376  template <typename FwdIter>
377  void
378  insert_table(std::string const& name,
379  intermediate_table& tbl,
380  bool in_prolog,
381  FwdIter pos,
382  cet::includer const& s)
383  {
384  extended_value const& xval = local_lookup(name, tbl, false, pos, s);
385  if (!xval.is_a(fhicl::TABLE)) {
387  << "key \"" << name << "\" does not refer to a table at "
388  << s.highlighted_whereis(pos) << "\n";
389  }
390  auto const& incoming = boost::any_cast<table_t const&>(xval.value);
391  for (auto incoming_item = incoming.cbegin(), e = incoming.cend();
392  incoming_item != e;
393  ++incoming_item) {
394  auto const& key = incoming_item->first;
395  auto element = incoming_item->second;
396  element.set_prolog(in_prolog);
397  element.set_src_info(s.src_whereis(pos));
398  tbl.insert(key, std::move(element));
399  }
400  }
401 
402  template <typename FwdIter>
403  void
404  seq_insert_sequence(std::string const& name,
405  intermediate_table& tbl,
406  bool in_prolog,
407  sequence_t& v,
408  FwdIter pos,
409  cet::includer const& s)
410  {
411  extended_value xval = local_lookup(name, tbl, false, pos, s);
412  if (!xval.is_a(fhicl::SEQUENCE)) {
413  throw fhicl::exception(fhicl::error::type_mismatch, "@sequence::")
414  << "key \"" << name << "\" does not refer to a sequence at "
415  << s.highlighted_whereis(pos) << "\n";
416  }
417  auto const& incoming = boost::any_cast<sequence_t const&>(xval.value);
418 #if GCC_IS_AT_LEAST(4, 9, 0) || \
419  defined(__clang__) /* Compiler supports C++2011 signature for ranged \
420  vector::insert() */
421  auto it = v.insert(v.end(), incoming.cbegin(), incoming.cend());
422 #else
423  v.insert(v.end(), incoming.cbegin(), incoming.cend());
424  auto it = v.end() - incoming.size();
425 #endif
426  int count = 0;
427  for (auto const e = v.end(); it != e; ++it, ++count) {
428  using std::to_string;
429  it->protection = Protection::NONE;
430  it->set_prolog(in_prolog);
431  it->set_src_info(s.src_whereis(pos));
432  }
433  }
434 
435  void
436  seq_insert_value(extended_value xval, sequence_t& v)
437  {
438  xval.protection = Protection::NONE;
439  v.emplace_back(std::move(xval));
440  }
441 
442  void
443  map_erase(std::string const& name, table_t& t)
444  {
445  auto const i = t.find(name);
446  if (i != t.end()) {
447  switch (i->second.protection) {
448  case Protection::NONE:
449  t.erase(name);
450  case Protection::PROTECT_IGNORE:
451  break;
452  case Protection::PROTECT_ERROR:
454  << "Unable to erase " << name << " due to protection.\n";
455  }
456  }
457  }
458 
459  template <typename FwdIter>
460  void
461  map_erase_loc(std::string const& name,
462  table_t& t,
463  FwdIter pos,
464  cet::includer const& s)
465  {
466  try {
467  map_erase(name, t);
468  }
469  catch (fhicl::exception& e) {
470  throw fhicl::exception(
471  fhicl::error::parse_error, "Error in erase attempt:", e)
472  << " at " << s.highlighted_whereis(pos) << '\n';
473  }
474  }
475 
476  // ----------------------------------------------------------------------
477 
478  template <class FwdIter, class Skip>
479  struct value_parser;
480 
481  template <class FwdIter, class Skip>
482  struct document_parser;
483 
484  // ----------------------------------------------------------------------
485 
486  template <class FwdIter, class Skip>
487  struct value_parser : qi::grammar<FwdIter, extended_value(), Skip> {
488  using atom_token = qi::rule<FwdIter, atom_t(), Skip>;
489  using complex_token = qi::rule<FwdIter, complex_t(), Skip>;
490  using sequence_token = qi::rule<FwdIter, sequence_t(), Skip>;
491  using table_token = qi::rule<FwdIter, table_t(), Skip>;
492  using value_token = qi::rule<FwdIter, extended_value(), Skip>;
493 
494  // default c'tor:
495  value_parser();
496 
497  // data member:
498  extended_value v;
499 
500  // parser rules:
501  atom_token nil, boolean;
502  atom_token inf;
503  atom_token squoted, dquoted;
504  atom_token number, string, name, catchall;
505  atom_token id;
506  complex_token complex;
507  sequence_token sequence;
508  table_token table;
509  value_token value;
510 
511  }; // value_parser
512 
513  // ----------------------------------------------------------------------
514 
515  template <class FwdIter, class Skip>
516  struct document_parser : qi::grammar<FwdIter, void(), Skip> {
517  using val_parser = value_parser<FwdIter, Skip>;
518 
519  using atom_token = typename val_parser::atom_token;
520  using sequence_token = typename val_parser::sequence_token;
521  using table_token = typename val_parser::table_token;
522  using value_token = typename val_parser::value_token;
523  using nothing_token = qi::rule<FwdIter, void(), Skip>;
524 
525  document_parser(cet::includer const& s);
526 
527  // data members:
528  bool in_prolog;
529  intermediate_table tbl;
530  val_parser vp;
531 
532  // parser rules:
533  atom_token name, qualname, noskip_qualname, localref, dbref;
534  sequence_token sequence;
535  table_token table;
536  value_token value;
537  nothing_token prolog, document;
538 
539  }; // document_parser
540 
541  // ----------------------------------------------------------------------
542 
543  template <class FwdIter, class Skip>
544  value_parser<FwdIter, Skip>::value_parser()
545  : value_parser::base_type{value}, v()
546  {
547  nil =
548  lexeme[(qi::string("@nil") >>
549  !(graph - char_(",]}")))[_val = phx::bind(canon_nil, qi::_1)]];
550  boolean = lexeme[(qi::string("true") | qi::string("false")) >>
551  !(graph - char_(",]}"))];
552  inf = lexeme[-(qi::string("+") | qi::string("-")) >>
553  qi::string("infinity") >> !(graph - char_("),]}"))];
554  squoted = lexeme[char_('\'') >> *(char_ - char_('\'')) >> char_('\'') >>
555  !(graph - char_(",]}"))];
556  dquoted =
557  lexeme[raw[char_('\"') >> *(qi::string("\\\"") | (char_ - char_('\"'))) >>
558  char_('\"') >> !(graph - char_(",]}"))]];
559  number =
560  (fhicl::uint[_val = phx::bind(canon_num, qi::_1)] |
561  inf[_val = phx::bind(canon_inf, qi::_1)] | fhicl::real[_val = qi::_1] |
562  fhicl::hex[_val = qi::_1] | fhicl::bin[_val = qi::_1]);
563  string = (fhicl::ass | fhicl::dss | squoted |
564  dquoted)[_val = phx::bind(canon_str, ref(qi::_1))];
565  name = fhicl::ass[_val = qi::_1];
566  complex = (lit('(') > number > lit(',') > number >
567  lit(')'))[_val = phx::bind(cplx, qi::_1, qi::_2)];
568  sequence = lit('[') > -(value % ',') > lit(']');
569  table =
570  lit('{') >
571  *((name >> fhicl::binding >>
572  value)[phx::bind(map_insert, ref(qi::_1), qi::_2, ref(qi::_3), _val)] |
573  (name >>
574  (lit(':') > lit("@erase")))[phx::bind(map_erase, ref(qi::_1), _val)]) >
575  lit('}');
576  id = lit("@id::") > no_skip[fhicl::dbid][_val = qi::_1];
577  catchall = shims::catchall[_val = phx::bind(canon_str, ref(qi::_1))];
578  value = (nil[_val = phx::bind(xvalue_vp, false, NIL, qi::_1)] |
579  boolean[_val = phx::bind(xvalue_vp, false, BOOL, qi::_1)] |
580  number[_val = phx::bind(xvalue_vp, false, NUMBER, qi::_1)] |
581  complex[_val = phx::bind(xvalue_vp, false, COMPLEX, qi::_1)] |
582  string[_val = phx::bind(xvalue_vp, false, STRING, qi::_1)] |
583  sequence[_val = phx::bind(xvalue_vp, false, SEQUENCE, qi::_1)] |
584  table[_val = phx::bind(xvalue_vp, false, TABLE, qi::_1)] |
585  id[_val = phx::bind(xvalue_vp, false, TABLEID, qi::_1)] |
586  catchall[_val = phx::bind(xvalue_vp, false, STRING, qi::_1)]);
587  nil.name("nil token");
588  boolean.name("boolean token");
589  inf.name("inf token");
590  squoted.name("squoted token");
591  dquoted.name("dquoted token");
592  number.name("number atom");
593  string.name("string atom");
594  name.name("name atom");
595  complex.name("complex atom");
596  sequence.name("sequence");
597  table.name("table");
598  id.name("id atom");
599  value.name("value");
600  catchall.name("catchall atom");
601  } // value_parser c'tor
602 
603  // ----------------------------------------------------------------------
604 
605  template <class FwdIter, class Skip>
606  document_parser<FwdIter, Skip>::document_parser(cet::includer const& s)
607  : document_parser::base_type(document), in_prolog(false), tbl(), vp()
608  {
609  using iter_t = cet::includer::const_iterator;
610  name = fhicl::ass;
611  qualname =
612  fhicl::ass[_val = qi::_1] >>
613  *((char_('.') > fhicl::ass)[_val += qi::_1 + qi::_2] |
614  (char_('[') > fhicl::uint >
615  char_(']'))[_val += qi::_1 + qi::_2 + qi::_3]); // Whitespace permitted
616  // before, and around
617  // delimiters ( '.',
618  // '[', ']').
619  noskip_qualname =
620  no_skip[fhicl::ass][_val = qi::_1] >>
621  *((char_('.') > fhicl::ass)[_val += qi::_1 + qi::_2] |
622  (char_('[') > fhicl::uint >
623  char_(']'))[_val += qi::_1 + qi::_2 + qi::_3]); // Whitespace permitted
624  // around delimiters
625  // ('.', '[', ']')
626  // only.
627  localref = lit("@local::") > noskip_qualname;
628  dbref = lit("@db::") > noskip_qualname;
629  // Can't use simple, "list context" due to the possibility of one of
630  // the list elements actually returning multiple elements.
631  sequence =
632  lit('[') > -(((value[phx::bind(seq_insert_value, ref(qi::_1), _val)]) |
633  ((iter_pos >> lit("@sequence::")) >
634  noskip_qualname)[phx::bind(&seq_insert_sequence<iter_t>,
635  ref(qi::_2),
636  ref(tbl),
637  ref(in_prolog),
638  _val,
639  qi::_1,
640  ref(s))])) >
641  *(lit(',') > ((value[phx::bind(seq_insert_value, ref(qi::_1), _val)]) |
642  ((iter_pos >> lit("@sequence::")) >
643  noskip_qualname)[phx::bind(&seq_insert_sequence<iter_t>,
644  ref(qi::_2),
645  ref(tbl),
646  ref(in_prolog),
647  _val,
648  qi::_1,
649  ref(s))])) > lit(']');
650  table = lit('{') >
651  *((iter_pos >> name >> fhicl::binding >>
652  value)[phx::bind(&map_insert_loc<iter_t>,
653  ref(qi::_2),
654  qi::_3,
655  ref(qi::_4),
656  _val,
657  qi::_1,
658  ref(s))] |
659  (iter_pos >> name >> (lit(':') > lit("@erase")))[phx::bind(
660  &map_erase_loc<iter_t>, ref(qi::_2), _val, qi::_1, ref(s))] |
661  ((iter_pos >> lit("@table::")) >
662  noskip_qualname)[phx::bind(&insert_table_in_table<iter_t>,
663  ref(qi::_2),
664  ref(tbl),
665  ref(in_prolog),
666  _val,
667  qi::_1,
668  ref(s))]) > lit('}');
669  // Clang does not like this (multiple unsequenced modifications to '_val'
670  // [-Werror,-Wunsequenced]) TEMPORARILY wrap until validity checked
671 #ifdef __clang__
672 #pragma clang diagnostic push
673 #pragma clang diagnostic ignored "-Wunsequenced"
674 #endif
675  value =
676  ((iter_pos >> vp.nil)
677  [_val = phx::bind(
678  &xvalue_dp<iter_t>, ref(in_prolog), NIL, qi::_2, qi::_1, ref(s))] |
679  (iter_pos >> vp.boolean)
680  [_val = phx::bind(
681  &xvalue_dp<iter_t>, ref(in_prolog), BOOL, qi::_2, qi::_1, ref(s))] |
682  (iter_pos >> vp.number)[_val = phx::bind(&xvalue_dp<iter_t>,
683  ref(in_prolog),
684  NUMBER,
685  qi::_2,
686  qi::_1,
687  ref(s))] |
688  (iter_pos >> vp.complex)[_val = phx::bind(&xvalue_dp<iter_t>,
689  ref(in_prolog),
690  COMPLEX,
691  qi::_2,
692  qi::_1,
693  ref(s))] |
694  (iter_pos >> vp.string)[_val = phx::bind(&xvalue_dp<iter_t>,
695  ref(in_prolog),
696  STRING,
697  qi::_2,
698  qi::_1,
699  ref(s))] |
700  (iter_pos >> localref)[_val = phx::bind(&local_lookup<iter_t>,
701  qi::_2,
702  ref(tbl),
703  ref(in_prolog),
704  qi::_1,
705  ref(s))] |
706  (iter_pos >> dbref)[_val = phx::bind(&database_lookup<iter_t>,
707  qi::_2,
708  ref(tbl),
709  ref(in_prolog),
710  qi::_1,
711  ref(s))] |
712  (iter_pos >> vp.id)[_val = phx::bind(&xvalue_dp<iter_t>,
713  ref(in_prolog),
714  TABLEID,
715  qi::_2,
716  qi::_1,
717  ref(s))] |
718  (iter_pos >> sequence)[_val = phx::bind(&xvalue_dp<iter_t>,
719  ref(in_prolog),
720  SEQUENCE,
721  qi::_2,
722  qi::_1,
723  ref(s))] |
724  (iter_pos >> table)[_val = phx::bind(&xvalue_dp<iter_t>,
725  ref(in_prolog),
726  TABLE,
727  qi::_2,
728  qi::_1,
729  ref(s))] |
730  (iter_pos >> vp.catchall)[_val = phx::bind(&xvalue_dp<iter_t>,
731  ref(in_prolog),
732  STRING,
733  qi::_2,
734  qi::_1,
735  ref(s))]);
736 #ifdef __clang__
737 #pragma clang diagnostic pop
738 #endif
739  prolog = lit("BEGIN_PROLOG")[phx::bind(rebool, ref(in_prolog), true)] >
740  *((iter_pos >> qualname >> fhicl::binding >>
741  value)[phx::bind(&tbl_insert<iter_t>,
742  ref(qi::_2),
743  qi::_3,
744  ref(qi::_4),
745  ref(tbl),
746  qi::_1,
747  ref(s))] |
748  (iter_pos >> qualname >>
749  (lit(':') > lit("@erase")))[phx::bind(&tbl_erase<iter_t>,
750  qi::_2,
751  ref(tbl),
752  ref(in_prolog),
753  qi::_1,
754  ref(s))] |
755  ((iter_pos >> lit("@table::")) >
756  noskip_qualname)[phx::bind(&insert_table<iter_t>,
757  qi::_2,
758  ref(tbl),
759  ref(in_prolog),
760  qi::_1,
761  ref(s))]) >
762  lit("END_PROLOG")[phx::bind(rebool, ref(in_prolog), false)];
763  document =
764  (*prolog) >> *((iter_pos >> qualname >> fhicl::binding >>
765  value)[phx::bind(&tbl_insert<iter_t>,
766  ref(qi::_2),
767  qi::_3,
768  ref(qi::_4),
769  ref(tbl),
770  qi::_1,
771  ref(s))] |
772  (iter_pos >> qualname >>
773  (lit(':') > lit("@erase")))[phx::bind(&tbl_erase<iter_t>,
774  qi::_2,
775  ref(tbl),
776  ref(in_prolog),
777  qi::_1,
778  ref(s))] |
779  ((iter_pos >> lit("@table::")) >
780  noskip_qualname)[phx::bind(&insert_table<iter_t>,
781  qi::_2,
782  ref(tbl),
783  ref(in_prolog),
784  qi::_1,
785  ref(s))]);
786  name.name("name atom");
787  localref.name("localref atom");
788  dbref.name("dbref atom");
789  qualname.name("qualified name");
790  noskip_qualname.name("qualified name (no pre-skip)");
791  sequence.name("sequence");
792  table.name("table");
793  value.name("value");
794  prolog.name("prolog");
795  document.name("document");
796  } // document_parser c'tor
797 }
798 
799 // ----------------------------------------------------------------------
800 
801 bool
802 fhicl::parse_value_string(std::string const& s,
803  extended_value& result,
804  std::string& unparsed)
805 {
806  typedef std::string::const_iterator iter_t;
807  typedef qi::rule<iter_t> ws_t;
808  ws_t whitespace = space | lit('#') >> *(char_ - eol) >> eol |
809  lit("//") >> *(char_ - eol) >> eol;
810  value_parser<iter_t, ws_t> p;
811  iter_t begin = s.begin();
812  iter_t const end = s.end();
813  bool const b =
814  qi::phrase_parse(begin, end, p >> *whitespace, whitespace, result) &&
815  begin == end;
816  unparsed = std::string(begin, end);
817  return b;
818 } // parse_value_string()
819 
820 // ----------------------------------------------------------------------
821 
822 namespace {
823  void
824  parse_document_(cet::includer s, intermediate_table& result)
825  {
826  using namespace std::string_literals;
827  typedef cet::includer::const_iterator iter_t;
828  typedef qi::rule<iter_t> ws_t;
829  ws_t whitespace = space | lit('#') >> *(char_ - eol) >> eol |
830  lit("//") >> *(char_ - eol) >> eol;
831  document_parser<iter_t, ws_t> p(s);
832  iter_t begin = s.begin();
833  iter_t const end = s.end();
834  bool b = false;
835  try {
836  b = qi::phrase_parse(begin, end, p, whitespace);
837  }
838  catch (qi::expectation_failure<iter_t> const& e) {
839  begin = e.first;
840  }
841  std::string unparsed(begin, end);
842  if (b && unparsed.empty()) {
843  result = p.tbl;
844  } else {
845  auto e = fhicl::exception(fhicl::parse_error, "detected at or near")
846  << s.highlighted_whereis(begin) << "\n";
847  if (unparsed.find("BEGIN_PROLOG"s) == 0ull) {
848  e << "PROLOG blocks must be both contiguous and not nested.\n";
849  }
850  throw e;
851  }
852  }
853 }
854 
855 void
856 fhicl::parse_document(std::string const& filename,
857  cet::filepath_maker& maker,
858  intermediate_table& result)
859 {
860  parse_document_(cet::includer(filename, maker), result);
861 } // parse_document()
862 
863 void
864 fhicl::parse_document(std::istream& is,
865  cet::filepath_maker& maker,
866  intermediate_table& result)
867 {
868  parse_document_(cet::includer(is, maker), result);
869 } // parse_document()
870 
871 // ======================================================================
Float_t s
Definition: plot.C:23
intermediate_table::complex_t complex_t
size_t erase(Key const &key)
Definition: stdmap_shims.h:259
bool parse_value_string(std::string const &s, extended_value &v, std::string &unparsed)
Definition: parse.cc:802
Raw data description.
Definition: RawTypes.h:6
auto lit(char arg)
Definition: parse_shims.h:11
void erase(std::string const &name, bool in_prolog=false)
Protection
Definition: Protection.h:7
iterator end()
Definition: stdmap_shims.h:177
Int_t max
Definition: plot.C:27
TCanvas * c1
Definition: plotHisto.C:7
intermediate_table::const_iterator const_iterator
TCanvas * c2
Definition: plot_hist.C:75
void set_src_info(std::string const &src)
parameter set interface
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
bool is_a(value_tag t) const
extended_value const & find(std::string const &name) const
static std::string canon_nil()
Definition: coding.cc:30
float bin[41]
Definition: plottest35.C:14
extended_value::table_t table_t
Definition: parse.cc:74
fhicl::extended_value::sequence_t sequence_t
intermediate_table::atom_t atom_t
bool insert(std::string const &name, bool in_prolog, value_tag tag, boost::any const &value)
extended_value::atom_t atom_t
Definition: parse.cc:71
std::string value(boost::any const &)
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
Definition: BitMask.h:187
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
std::string pretty_src_info() const
extended_value::complex_t complex_t
Definition: parse.cc:72
Float_t e
Definition: plot.C:34
void set_prolog(bool new_prolog_state)
iterator find(Key const &key)
Definition: stdmap_shims.h:231
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
void parse_document(std::string const &filename, cet::filepath_maker &maker, intermediate_table &result)
Definition: parse.cc:856
extended_value::sequence_t sequence_t
Definition: parse.cc:73