artdaq_mfextensions  v1_06_02
ma_parse.cpp
1 
2 #include "ErrorHandler/MessageAnalyzer/ma_parse.h"
3 
4 #include "ErrorHandler/MessageAnalyzer/ma_types.h"
5 
6 #include "ErrorHandler/MessageAnalyzer/ma_boolean_andexpr.h"
7 #include "ErrorHandler/MessageAnalyzer/ma_boolean_cond.h"
8 #include "ErrorHandler/MessageAnalyzer/ma_boolean_expr.h"
9 
10 #include "ErrorHandler/MessageAnalyzer/ma_domain_andexpr.h"
11 #include "ErrorHandler/MessageAnalyzer/ma_domain_cond.h"
12 #include "ErrorHandler/MessageAnalyzer/ma_domain_expr.h"
13 
14 #include "ErrorHandler/MessageAnalyzer/ma_cond_test_andexpr.h"
15 #include "ErrorHandler/MessageAnalyzer/ma_cond_test_expr.h"
16 #include "ErrorHandler/MessageAnalyzer/ma_cond_test_primary.h"
17 
18 #include "ErrorHandler/MessageAnalyzer/ma_rule.h"
19 
20 #include <boost/any.hpp>
21 #include <boost/spirit/include/phoenix_bind.hpp>
22 #include <boost/spirit/include/phoenix_core.hpp>
23 #include <boost/spirit/include/phoenix_operator.hpp>
24 #include <boost/spirit/include/qi.hpp>
25 
26 namespace ascii = ::boost::spirit::ascii;
27 namespace phx = ::boost::phoenix;
28 namespace qi = ::boost::spirit::qi;
29 namespace ql = ::boost::spirit::qi::labels;
30 
31 using ascii::char_;
32 using ascii::digit;
33 using ascii::graph;
34 using ascii::no_case;
35 using ascii::space;
36 
37 using phx::ref;
38 //using phx::bind;
39 
40 using qi::bool_;
41 using qi::double_;
42 using qi::eol;
43 using qi::int_;
44 using qi::lexeme;
45 using qi::lit;
46 using qi::locals;
47 using qi::no_skip;
48 using qi::raw;
49 using qi::skip;
50 
51 //using namespace qi::labels;
52 
53 using novadaq::errorhandler::CO_E;
54 using novadaq::errorhandler::CO_G;
55 using novadaq::errorhandler::CO_GE;
56 using novadaq::errorhandler::CO_L;
57 using novadaq::errorhandler::CO_LE;
58 using novadaq::errorhandler::CO_NE;
59 using novadaq::errorhandler::compare_op_t;
60 using novadaq::errorhandler::cond_arg_t;
61 using novadaq::errorhandler::cond_idx_t;
73 using novadaq::errorhandler::NONE;
74 using novadaq::errorhandler::SOURCE;
75 using novadaq::errorhandler::TARGET;
76 
77 // ------------------------------------------------------------------
78 
79 namespace novadaq {
80 namespace errorhandler {
81 template<class FwdIter, class Skip>
83 
84 template<class FwdIter, class Skip>
86 
87 template<class FwdIter, class Skip>
89 
90 class ma_rule;
91 } // namespace errorhandler
92 } // namespace novadaq
93 
94 // ------------------------------------------------------------------
95 
96 static void
97 insert_domain_andexpr(ma_domain_expr& expr, ma_domain_andexpr const& andexpr)
98 {
99  expr.insert_andexpr(andexpr);
100 }
101 
102 static void
103 insert_domain_cond(ma_domain_andexpr& andexpr, ma_domain_cond const& cond)
104 {
105  andexpr.insert_cond(cond);
106 }
107 
108 static void
109 insert_domain_expr(ma_domain_cond& cond, ma_domain_expr const& expr)
110 {
111  cond.insert_expr(expr);
112 }
113 
114 static void
115 insert_cond_arg(ma_domain_cond& cond, std::string const& name, char arg, ma_rule* rule)
116 {
117  // update condition's notification list
118  rule->update_notify_list(name, (arg == 's') ? SOURCE : TARGET);
119 
120  // push the condition ptr into domain_cond
121  cond.insert_cond_arg(rule->get_cond_idx(name), (arg == 's') ? SOURCE : TARGET, rule->get_cond_size());
122 }
123 
124 static void
125 insert_str_cond(ma_domain_cond& cond, std::string const& str)
126 {
127  cond.insert_str_cond(str);
128 }
129 
130 // ------------------------------------------------------------------
131 
132 template<class FwdIter, class Skip>
134  : qi::grammar<FwdIter, ma_domain_expr(), Skip>
135 {
136  // default c'tor
137  domain_expr_parser(ma_rule* rule);
138 
139  // data member
140  qi::rule<FwdIter, ma_domain_expr(), Skip> domain_expr;
141  qi::rule<FwdIter, ma_domain_andexpr(), Skip> domain_andexpr;
142  qi::rule<FwdIter, ma_domain_cond(), locals<std::string>, Skip> domain_cond;
143 
144  qi::rule<FwdIter, std::string(), Skip> key;
145  qi::rule<FwdIter, std::string(), Skip> keywords;
146  qi::rule<FwdIter, std::string(), Skip> str;
147 };
148 
149 // ------------------------------------------------------------------
150 
151 template<class FwdIter, class Skip>
153  : domain_expr_parser::base_type(domain_expr)
154 {
155  domain_expr =
156  domain_andexpr[phx::bind(&insert_domain_andexpr, ql::_val, ql::_1)] % "OR";
157 
158  domain_andexpr =
159  domain_cond[phx::bind(&insert_domain_cond, ql::_val, ql::_1)] % "AND";
160 
161  domain_cond =
162  (lit('(') >> domain_expr[phx::bind(&insert_domain_expr, ql::_val, ql::_1)] >> lit(')')) // '(' >> expr >> ')'
163  |
164  ((
165  (
166  key[ql::_a = ql::_1] >> ".$" >> char_("st")
167  [phx::bind(&insert_cond_arg, ql::_val, ql::_a, ql::_1, rule)]) %
168  '=') >>
169  -('=' >> (str[phx::bind(&insert_str_cond, ql::_val, ql::_1)] | "ANY"))) // cond1.$x = cond2.$y = ... -( = "str_cond" )
170  // cond1.$x = cond2.$y = ... -( = ANY )
171  ;
172 
173  keywords = no_case["AND"] | no_case["OR"] | no_case["ANY"];
174 
175  key = qi::lexeme[char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")] - keywords;
176  ;
177 
178  str = qi::lexeme['\'' >> +(ascii::char_ - '\'') >> '\''];
179 }
180 
181 // ------------------------------------------------------------------
182 
183 static void
184 insert_boolean_andexpr(ma_boolean_expr& expr, ma_boolean_andexpr const& andexpr)
185 {
186  expr.insert(andexpr);
187 }
188 
189 static void
190 insert_boolean_cond(ma_boolean_andexpr& andexpr, ma_boolean_cond const& cond)
191 {
192  andexpr.insert(cond);
193 }
194 
195 static void
196 insert_boolean_expr(ma_boolean_cond& cond, ma_boolean_expr const& expr)
197 {
198  cond.insert_expr(expr);
199 }
200 
201 static void
202 insert_primitive_cond(ma_boolean_cond& cond, std::string const& name, ma_rule* rule)
203 {
204  // 1. first insert the condition ptr to the corresponding rule
205  // such that the condition has an index in the rule
206  // NOTE* that the insertion of condition ptr only happens when
207  // parsing the boolean expression
208  // 2. then insert the (ptr, idx) pair to the boolean_cond
209  cond.insert_cond(rule->insert_condition_ptr(name, true));
210 }
211 
212 static void
213 insert_ext_func(ma_boolean_cond& cond, std::string const& function, std::string const& name, char cond_arg, std::vector<boost::any> const& func_args, ma_rule* rule)
214 {
215  cond.insert_ext_func(rule->insert_condition_ptr(name, false /*non-primitive*/), (cond_arg == 's') ? SOURCE : ((cond_arg == 't') ? TARGET : NONE), func_args, function);
216 }
217 
218 static void
219 insert_compare_op_double(ma_boolean_cond& cond, compare_op_t op, double rhv)
220 {
221  cond.insert_compare_op_double(op, rhv);
222 }
223 
224 static void
225 insert_compare_op_bool(ma_boolean_cond& cond, compare_op_t op, bool rhv)
226 {
227  if ((op != CO_E) && (op != CO_NE))
228  throw std::runtime_error("error in parsing rule: booleans can only use == or !=");
229 
230  cond.insert_compare_op_bool(op, rhv);
231 }
232 
233 static void
234 insert_compare_op_string(ma_boolean_cond& cond, compare_op_t op, std::string rhv)
235 {
236  cond.insert_compare_op_string(op, rhv);
237 }
238 
239 // ------------------------------------------------------------------
240 
241 using boost::any;
242 typedef std::vector<any> anys;
243 
244 template<class FwdIter, class Skip>
246  : qi::grammar<FwdIter, ma_boolean_expr(), Skip>
247 {
248  // default c'tor
249  boolean_expr_parser(ma_rule* rule);
250 
251  // data member
252  qi::rule<FwdIter, ma_boolean_expr(), Skip> boolean_expr;
253  qi::rule<FwdIter, ma_boolean_andexpr(), Skip> boolean_andexpr;
254  qi::rule<FwdIter, ma_boolean_cond(), locals<std::string, char, compare_op_t, std::string, anys>, Skip> boolean_cond;
255 
256  qi::rule<FwdIter, std::string(), Skip> key;
257  qi::rule<FwdIter, std::string(), Skip> str;
258  qi::rule<FwdIter, std::string(), Skip> keywords;
259  qi::rule<FwdIter, compare_op_t(), Skip> compare_op;
260 
261  qi::rule<FwdIter, any(), Skip> arg;
262  qi::rule<FwdIter, anys(), Skip> args;
263 };
264 
265 // ------------------------------------------------------------------
266 
267 template<class FwdIter, class Skip>
269  : boolean_expr_parser::base_type(boolean_expr)
270 {
271  boolean_expr =
272  boolean_andexpr[phx::bind(&insert_boolean_andexpr, ql::_val, ql::_1)] % "||";
273 
274  boolean_andexpr =
275  boolean_cond[phx::bind(&insert_boolean_cond, ql::_val, ql::_1)] % "&&";
276 
277  boolean_cond =
278  (lit('(') >> boolean_expr[phx::bind(&insert_boolean_expr, ql::_val, ql::_1)] >> ')') // '(' >> expr >> ')'
279  |
280  (key[ql::_a = ql::_1] >> lit('(') >> key[ql::_d = ql::_1] >> -(".$" >> char_("st")[ql::_b = ql::_1]) >> -(',' >> args[ql::_e = ql::_1]) >> lit(')')[phx::bind(&insert_ext_func, ql::_val, ql::_a, ql::_d, ql::_b, ql::_e, rule)]
281 
282  >> -(compare_op[ql::_c = ql::_1] >> (double_[phx::bind(&insert_compare_op_double, ql::_val, ql::_c, ql::_1)] | bool_[phx::bind(&insert_compare_op_bool, ql::_val, ql::_c, ql::_1)] | str[phx::bind(&insert_compare_op_string, ql::_val, ql::_c, ql::_1)]))) // custom_function(cond.$st)
283  |
284  key[phx::bind(&insert_primitive_cond, ql::_val, ql::_1, rule)]
285  // Cond
286  ;
287 
288  args = (arg % ',');
289 
290  arg = double_[ql::_val = ql::_1] | bool_[ql::_val = ql::_1] | str[ql::_val = ql::_1];
291 
292  keywords = no_case["AND"] | no_case["OR"];
293 
294  key = qi::lexeme[char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")] - keywords;
295 
296  str = qi::lexeme['\'' >> +(char_ - '\'') >> '\''];
297 
298  compare_op = lit("==")[ql::_val = CO_E] | lit("!=")[ql::_val = CO_NE] | lit("<=")[ql::_val = CO_LE] | lit(">=")[ql::_val = CO_GE] | lit("<")[ql::_val = CO_L] | lit(">")[ql::_val = CO_G];
299 }
300 
301 // ------------------------------------------------------------------
302 
303 static void
304 set_boolean_expr(ma_boolean_expr& expr, ma_rule* rule)
305 {
306  rule->set_boolean_expr(expr);
307 }
308 
309 static void
310 set_domain_expr(ma_domain_expr& expr, ma_rule* rule)
311 {
312  rule->set_domain_expr(expr);
313 }
314 
315 // ------------------------------------------------------------------
316 
317 bool novadaq::errorhandler::parse_condition_expr(std::string const& s, ma_rule* rule)
318 {
319  typedef std::string::const_iterator iter_t;
320  typedef ascii::space_type ws_t;
321 
322  boolean_expr_parser<iter_t, ws_t> boolean_p(rule);
323  domain_expr_parser<iter_t, ws_t> domain_p(rule);
324 
325  iter_t begin = s.begin();
326  iter_t const end = s.end();
327 
328  bool b = qi::phrase_parse(
329  begin, end, boolean_p[phx::bind(&set_boolean_expr, ql::_1, rule)] >> -("WHERE" >> domain_p[phx::bind(&set_domain_expr, ql::_1, rule)]), space) &&
330  begin == end;
331 
332  return b;
333 }
334 
335 // ------------------------------------------------------------------
336 // Condition test expression parser
337 // ------------------------------------------------------------------
338 
339 static void
340 insert_test_primary(ma_cond_test_andexpr& andexpr, ma_cond_test_primary const& primary)
341 {
342  andexpr.insert(primary);
343 }
344 
345 static void
346 insert_test_andexpr(ma_cond_test_expr& expr, ma_cond_test_andexpr const& andexpr)
347 {
348  expr.insert(andexpr);
349 }
350 
351 static void
352 insert_test_expr(ma_cond_test_primary& primary, ma_cond_test_expr const& expr)
353 {
354  primary.insert_expr(expr);
355 }
356 
357 static void
358 insert_test_func(ma_cond_test_primary& primary, std::string const& function, std::vector<boost::any> const& func_args)
359 {
360  primary.insert_func(function, func_args);
361 }
362 
363 static void
364 insert_test_compare_op(ma_cond_test_primary& primary, compare_op_t op, boost::any const& rhv)
365 {
366  primary.insert_compare_op(op, rhv);
367 }
368 
369 // ------------------------------------------------------------------
370 
371 template<typename T>
372 struct strict_real_policies : qi::real_policies<T>
373 {
374  static bool const expect_dot = true;
375 };
376 
377 template<class FwdIter, class Skip>
379  : qi::grammar<FwdIter, ma_cond_test_expr(), Skip>
380 {
381  // default c'tor
382  cond_test_expr_parser();
383 
384  // data member
385  qi::rule<FwdIter, ma_cond_test_expr(), Skip> test_expr;
386  qi::rule<FwdIter, ma_cond_test_andexpr(), Skip> test_andexpr;
387  qi::rule<FwdIter, ma_cond_test_primary(), locals<std::string, anys_t, compare_op_t>, Skip> test_primary;
388 
389  qi::rule<FwdIter, std::string(), Skip> key;
390  qi::rule<FwdIter, std::string(), Skip> str;
391  qi::rule<FwdIter, std::string(), Skip> keywords;
392  qi::rule<FwdIter, compare_op_t(), Skip> compare_op;
393 
394  qi::rule<FwdIter, any(), Skip> value;
395  qi::rule<FwdIter, anys(), Skip> values;
396 
397  qi::real_parser<double, strict_real_policies<double> > real;
398 };
399 
400 // ------------------------------------------------------------------
401 
402 template<class FwdIter, class Skip>
404  : cond_test_expr_parser::base_type(test_expr)
405 {
406  test_expr =
407  test_andexpr[phx::bind(&insert_test_andexpr, ql::_val, ql::_1)] % "||";
408 
409  test_andexpr =
410  test_primary[phx::bind(&insert_test_primary, ql::_val, ql::_1)] % "&&";
411 
412  test_primary =
413  (lit('(') >> test_expr[phx::bind(&insert_test_expr, ql::_val, ql::_1)] >> lit(')')) |
414  (key[ql::_a = ql::_1] >> lit('(') >> -values[ql::_b = ql::_1] >> lit(')')[phx::bind(&insert_test_func, ql::_val, ql::_a, ql::_b)] >> -(compare_op[ql::_c = ql::_1] >> value[phx::bind(&insert_test_compare_op, ql::_val, ql::_c, ql::_1)]));
415 
416  values = (value % ',');
417 
418  value = (int_[ql::_val = ql::_1] >> !char_(".eE")) | double_[ql::_val = ql::_1] | bool_[ql::_val = ql::_1] | str[ql::_val = ql::_1];
419 
420  keywords = no_case["AND"] | no_case["OR"];
421 
422  key = qi::lexeme[char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")] - keywords;
423 
424  str = qi::lexeme['\'' >> +(char_ - '\'') >> '\''];
425 
426  compare_op = lit("==")[ql::_val = CO_E] | lit("!=")[ql::_val = CO_NE] | lit("<=")[ql::_val = CO_LE] | lit(">=")[ql::_val = CO_GE] | lit("<")[ql::_val = CO_L] | lit(">")[ql::_val = CO_G];
427 }
428 
429 // ------------------------------------------------------------------
430 
431 bool novadaq::errorhandler::parse_condition_test(std::string const& s, ma_cond_test_expr& expr)
432 {
433  typedef std::string::const_iterator iter_t;
434  typedef ascii::space_type ws_t;
435 
436  if (s.empty()) return true;
437 
438  cond_test_expr_parser<iter_t, ws_t> test_p;
439 
440  iter_t begin = s.begin();
441  iter_t const end = s.end();
442 
443  bool b = qi::phrase_parse(begin, end, test_p, space, expr) && begin == end;
444 
445  return b;
446 }
boolean and-expression consists of a list of boolean elemental conditions connected with &#39;AND&#39; operat...