artdaq_mfextensions  v1_05_00
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_expr.h"
7 #include "ErrorHandler/MessageAnalyzer/ma_boolean_andexpr.h"
8 #include "ErrorHandler/MessageAnalyzer/ma_boolean_cond.h"
9 
10 #include "ErrorHandler/MessageAnalyzer/ma_domain_expr.h"
11 #include "ErrorHandler/MessageAnalyzer/ma_domain_andexpr.h"
12 #include "ErrorHandler/MessageAnalyzer/ma_domain_cond.h"
13 
14 #include "ErrorHandler/MessageAnalyzer/ma_cond_test_expr.h"
15 #include "ErrorHandler/MessageAnalyzer/ma_cond_test_andexpr.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/qi.hpp>
22 #include <boost/spirit/include/phoenix_bind.hpp>
23 #include <boost/spirit/include/phoenix_core.hpp>
24 #include <boost/spirit/include/phoenix_operator.hpp>
25 
26 
27 namespace ascii = ::boost::spirit::ascii;
28 namespace phx = ::boost::phoenix;
29 namespace qi = ::boost::spirit::qi;
30 namespace ql = ::boost::spirit::qi::labels;
31 
32 using ascii::char_;
33 using ascii::no_case;
34 using ascii::digit;
35 using ascii::graph;
36 using ascii::space;
37 
38 using phx::ref;
39 //using phx::bind;
40 
41 using qi::eol;
42 using qi::lexeme;
43 using qi::lit;
44 using qi::bool_;
45 using qi::int_;
46 using qi::double_;
47 using qi::no_skip;
48 using qi::raw;
49 using qi::skip;
50 using qi::locals;
51 
52 //using namespace qi::labels;
53 
65 using novadaq::errorhandler::cond_idx_t;
66 using novadaq::errorhandler::cond_arg_t;
67 using novadaq::errorhandler::compare_op_t;
68 using novadaq::errorhandler::SOURCE;
69 using novadaq::errorhandler::TARGET;
70 using novadaq::errorhandler::NONE;
71 using novadaq::errorhandler::CO_LE;
72 using novadaq::errorhandler::CO_GE;
73 using novadaq::errorhandler::CO_NE;
74 using novadaq::errorhandler::CO_E;
75 using novadaq::errorhandler::CO_L;
76 using novadaq::errorhandler::CO_G;
77 
78 
79 
80 // ------------------------------------------------------------------
81 
82 namespace novadaq
83 {
84  namespace errorhandler
85  {
86  template< class FwdIter, class Skip>
88 
89  template< class FwdIter, class Skip>
91 
92  template< class FwdIter, class Skip>
94 
95  class ma_rule;
96  }
97 }
98 
99 
100 // ------------------------------------------------------------------
101 
102 static void
103  insert_domain_andexpr( ma_domain_expr & expr
104  , ma_domain_andexpr const & andexpr )
105 {
106  expr.insert_andexpr(andexpr);
107 }
108 
109 static void
110  insert_domain_cond( ma_domain_andexpr & andexpr
111  , ma_domain_cond const & cond )
112 {
113  andexpr.insert_cond(cond);
114 }
115 
116 static void
117  insert_domain_expr( ma_domain_cond & cond
118  , ma_domain_expr const & expr )
119 {
120  cond.insert_expr(expr);
121 }
122 
123 static void
124  insert_cond_arg( ma_domain_cond & cond
125  , std::string const & name
126  , char arg
127  , ma_rule * rule )
128 {
129  // update condition's notification list
130  rule->update_notify_list( name
131  , (arg=='s') ? SOURCE : TARGET );
132 
133  // push the condition ptr into domain_cond
134  cond.insert_cond_arg ( rule->get_cond_idx(name)
135  , (arg=='s') ? SOURCE : TARGET
136  , rule->get_cond_size() );
137 }
138 
139 static void
140  insert_str_cond( ma_domain_cond & cond, std::string const & str )
141 {
142  cond.insert_str_cond( str );
143 }
144 
145 
146 // ------------------------------------------------------------------
147 
148 template< class FwdIter, class Skip >
150 : qi::grammar<FwdIter, ma_domain_expr(), Skip>
151 {
152 
153  // default c'tor
154  domain_expr_parser( ma_rule * rule );
155 
156  // data member
157  qi::rule<FwdIter, ma_domain_expr(), Skip> domain_expr;
158  qi::rule<FwdIter, ma_domain_andexpr(), Skip> domain_andexpr;
159  qi::rule<FwdIter, ma_domain_cond(), locals<std::string>, Skip> domain_cond;
160 
161  qi::rule<FwdIter, std::string(), Skip> key;
162  qi::rule<FwdIter, std::string(), Skip> keywords;
163  qi::rule<FwdIter, std::string(), Skip> str;
164 
165 };
166 
167 
168 // ------------------------------------------------------------------
169 
170 template< class FwdIter, class Skip >
173 : domain_expr_parser::base_type( domain_expr )
174 {
175  domain_expr =
176  domain_andexpr [phx::bind(&insert_domain_andexpr, ql::_val, ql::_1)]
177  % "OR"
178  ;
179 
180  domain_andexpr =
181  domain_cond [phx::bind(&insert_domain_cond, ql::_val, ql::_1)]
182  % "AND"
183  ;
184 
185  domain_cond =
186  (
187  lit('(')
188  >> domain_expr [phx::bind(&insert_domain_expr, ql::_val, ql::_1)]
189  >> lit(')')
190  ) // '(' >> expr >> ')'
191  |
192  (
193  (
194  (
195  key [ql::_a = ql::_1]
196  >> ".$"
197  >> char_("st")
198  [phx::bind(&insert_cond_arg, ql::_val, ql::_a, ql::_1, rule)]
199  ) % '='
200  ) >> -( '=' >> ( str [phx::bind(&insert_str_cond, ql::_val, ql::_1)]
201  | "ANY"
202  )
203  )
204  ) // cond1.$x = cond2.$y = ... -( = "str_cond" )
205  // cond1.$x = cond2.$y = ... -( = ANY )
206  ;
207 
208  keywords = no_case["AND"]
209  | no_case["OR"]
210  | no_case["ANY"]
211  ;
212 
213  key = qi::lexeme[char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")]
214  - keywords;
215  ;
216 
217  str = qi::lexeme['\'' >> +(ascii::char_ - '\'') >> '\''];
218 }
219 
220 
221 // ------------------------------------------------------------------
222 
223 static void
224  insert_boolean_andexpr( ma_boolean_expr & expr
225  , ma_boolean_andexpr const & andexpr )
226 {
227  expr.insert(andexpr);
228 }
229 
230 static void
231  insert_boolean_cond( ma_boolean_andexpr & andexpr
232  , ma_boolean_cond const & cond )
233 {
234  andexpr.insert(cond);
235 }
236 
237 static void
238  insert_boolean_expr( ma_boolean_cond & cond
239  , ma_boolean_expr const & expr )
240 {
241  cond.insert_expr(expr);
242 }
243 
244 static void
245  insert_primitive_cond( ma_boolean_cond & cond
246  , std::string const & name
247  , ma_rule * rule )
248 {
249  // 1. first insert the condition ptr to the corresponding rule
250  // such that the condition has an index in the rule
251  // NOTE* that the insertion of condition ptr only happens when
252  // parsing the boolean expression
253  // 2. then insert the (ptr, idx) pair to the boolean_cond
254  cond.insert_cond( rule->insert_condition_ptr( name, true ) );
255 }
256 
257 static void
258  insert_ext_func( ma_boolean_cond & cond
259  , std::string const & function
260  , std::string const & name
261  , char cond_arg
262  , std::vector<boost::any> const & func_args
263  , ma_rule * rule )
264 {
265  cond.insert_ext_func( rule->insert_condition_ptr( name, false /*non-primitive*/ )
266  , (cond_arg=='s') ? SOURCE : ((cond_arg=='t') ? TARGET : NONE)
267  , func_args
268  , function );
269 }
270 
271 static void
272  insert_compare_op_double( ma_boolean_cond & cond
273  , compare_op_t op
274  , double rhv )
275 {
276  cond.insert_compare_op_double( op, rhv );
277 }
278 
279 static void
280  insert_compare_op_bool ( ma_boolean_cond & cond
281  , compare_op_t op
282  , bool rhv )
283 {
284  if( (op != CO_E) && (op != CO_NE) )
285  throw std::runtime_error("error in parsing rule: booleans can only use == or !=");
286 
287  cond.insert_compare_op_bool( op, rhv );
288 }
289 
290 static void
291  insert_compare_op_string( ma_boolean_cond & cond
292  , compare_op_t op
293  , std::string rhv )
294 {
295  cond.insert_compare_op_string( op, rhv );
296 }
297 
298 // ------------------------------------------------------------------
299 
300 using boost::any;
301 typedef std::vector<any> anys;
302 
303 template< class FwdIter, class Skip >
305 : qi::grammar<FwdIter, ma_boolean_expr(), Skip>
306 {
307 
308  // default c'tor
309  boolean_expr_parser( ma_rule * rule );
310 
311  // data member
312  qi::rule<FwdIter, ma_boolean_expr(), Skip> boolean_expr;
313  qi::rule<FwdIter, ma_boolean_andexpr(), Skip> boolean_andexpr;
314  qi::rule<FwdIter, ma_boolean_cond()
315  , locals<std::string, char, compare_op_t, std::string, anys>
316  , Skip> boolean_cond;
317 
318  qi::rule<FwdIter, std::string(), Skip> key;
319  qi::rule<FwdIter, std::string(), Skip> str;
320  qi::rule<FwdIter, std::string(), Skip> keywords;
321  qi::rule<FwdIter, compare_op_t(), Skip> compare_op;
322 
323  qi::rule<FwdIter, any(), Skip> arg;
324  qi::rule<FwdIter, anys(), Skip> args;
325 
326 };
327 
328 
329 // ------------------------------------------------------------------
330 
331 template< class FwdIter, class Skip >
334 : boolean_expr_parser::base_type( boolean_expr )
335 {
336  boolean_expr =
337  boolean_andexpr [phx::bind(&insert_boolean_andexpr, ql::_val, ql::_1)]
338  % "||"
339  ;
340 
341  boolean_andexpr =
342  boolean_cond [phx::bind(&insert_boolean_cond, ql::_val, ql::_1)]
343  % "&&"
344  ;
345 
346  boolean_cond =
347  ( lit('(')
348  >> boolean_expr [phx::bind(&insert_boolean_expr,ql::_val,ql::_1)]
349  >> ')'
350  ) // '(' >> expr >> ')'
351  |
352  (
353  key [ ql::_a = ql::_1 ]
354  >> lit('(') >> key [ ql::_d = ql::_1 ]
355  >> -( ".$" >> char_("st") [ ql::_b = ql::_1 ] )
356  >> -( ',' >> args [ ql::_e = ql::_1 ] )
357  >> lit(')') [ phx::bind( &insert_ext_func
358  , ql::_val, ql::_a, ql::_d, ql::_b, ql::_e, rule ) ]
359 
360  >> -( compare_op [ ql::_c = ql::_1 ]
361  >> (
362  double_ [ phx::bind( &insert_compare_op_double
363  , ql::_val, ql::_c, ql::_1 ) ]
364  | bool_ [ phx::bind( &insert_compare_op_bool
365  , ql::_val, ql::_c, ql::_1 ) ]
366  | str [ phx::bind( &insert_compare_op_string
367  , ql::_val, ql::_c, ql::_1 ) ]
368  )
369  )
370  ) // custom_function(cond.$st)
371  |
372  key [ phx::bind( &insert_primitive_cond, ql::_val, ql::_1, rule) ]
373  // Cond
374  ;
375 
376  args = ( arg % ',' )
377  ;
378 
379  arg = double_ [ ql::_val = ql::_1 ]
380  | bool_ [ ql::_val = ql::_1 ]
381  | str [ ql::_val = ql::_1 ]
382  ;
383 
384  keywords = no_case["AND"]
385  | no_case["OR"]
386  ;
387 
388  key = qi::lexeme[char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")]
389  - keywords
390  ;
391 
392  str = qi::lexeme['\'' >> +(char_ - '\'') >> '\'']
393  ;
394 
395  compare_op = lit("==") [ ql::_val = CO_E ]
396  | lit("!=") [ ql::_val = CO_NE ]
397  | lit("<=") [ ql::_val = CO_LE ]
398  | lit(">=") [ ql::_val = CO_GE ]
399  | lit("<" ) [ ql::_val = CO_L ]
400  | lit(">" ) [ ql::_val = CO_G ]
401  ;
402 }
403 
404 
405 // ------------------------------------------------------------------
406 
407 static void
408  set_boolean_expr( ma_boolean_expr & expr, ma_rule * rule )
409 {
410  rule->set_boolean_expr( expr );
411 }
412 
413 static void
414  set_domain_expr( ma_domain_expr & expr, ma_rule * rule )
415 {
416  rule->set_domain_expr( expr );
417 }
418 
419 
420 // ------------------------------------------------------------------
421 
422 bool
423  novadaq::errorhandler::parse_condition_expr ( std::string const & s
424  , ma_rule * rule )
425 {
426  typedef std::string::const_iterator iter_t;
427  typedef ascii::space_type ws_t;
428 
429  boolean_expr_parser<iter_t, ws_t> boolean_p(rule);
430  domain_expr_parser<iter_t, ws_t> domain_p(rule);
431 
432  iter_t begin = s.begin();
433  iter_t const end = s.end();
434 
435  bool b = qi::phrase_parse
436  (
437  begin, end
438  , boolean_p [phx::bind(&set_boolean_expr, ql::_1, rule)]
439  >> -( "WHERE" >> domain_p
440  [phx::bind(&set_domain_expr , ql::_1, rule)]
441  )
442  , space
443  )
444  && begin == end;
445 
446  return b;
447 }
448 
449 
450 // ------------------------------------------------------------------
451 // Condition test expression parser
452 // ------------------------------------------------------------------
453 
454 static void
455  insert_test_primary( ma_cond_test_andexpr & andexpr
456  , ma_cond_test_primary const & primary )
457 {
458  andexpr.insert( primary );
459 }
460 
461 static void
462  insert_test_andexpr( ma_cond_test_expr & expr
463  , ma_cond_test_andexpr const & andexpr )
464 {
465  expr.insert( andexpr );
466 }
467 
468 static void
469  insert_test_expr( ma_cond_test_primary & primary
470  , ma_cond_test_expr const & expr )
471 {
472  primary.insert_expr( expr );
473 }
474 
475 static void
476  insert_test_func( ma_cond_test_primary & primary
477  , std::string const & function
478  , std::vector<boost::any> const & func_args )
479 {
480  primary.insert_func( function, func_args );
481 }
482 
483 static void
484  insert_test_compare_op( ma_cond_test_primary & primary
485  , compare_op_t op
486  , boost::any const & rhv )
487 {
488  primary.insert_compare_op( op, rhv );
489 }
490 
491 
492 // ------------------------------------------------------------------
493 
494 template <typename T>
495 struct strict_real_policies : qi::real_policies<T>
496 {
497  static bool const expect_dot = true;
498 };
499 
500 
501 template< class FwdIter, class Skip >
503 : qi::grammar<FwdIter, ma_cond_test_expr(), Skip>
504 {
505 
506  // default c'tor
507  cond_test_expr_parser( );
508 
509  // data member
510  qi::rule<FwdIter, ma_cond_test_expr(), Skip> test_expr;
511  qi::rule<FwdIter, ma_cond_test_andexpr(), Skip> test_andexpr;
512  qi::rule<FwdIter, ma_cond_test_primary()
513  , locals<std::string, anys_t, compare_op_t>
514  , Skip> test_primary;
515 
516  qi::rule<FwdIter, std::string(), Skip> key;
517  qi::rule<FwdIter, std::string(), Skip> str;
518  qi::rule<FwdIter, std::string(), Skip> keywords;
519  qi::rule<FwdIter, compare_op_t(), Skip> compare_op;
520 
521  qi::rule<FwdIter, any(), Skip> value;
522  qi::rule<FwdIter, anys(), Skip> values;
523 
524  qi::real_parser< double, strict_real_policies<double> > real;
525 };
526 
527 
528 // ------------------------------------------------------------------
529 
530 template< class FwdIter, class Skip >
533 : cond_test_expr_parser::base_type( test_expr )
534 {
535  test_expr =
536  test_andexpr [phx::bind(&insert_test_andexpr, ql::_val, ql::_1)]
537  % "||"
538  ;
539 
540  test_andexpr =
541  test_primary [phx::bind(&insert_test_primary, ql::_val, ql::_1)]
542  % "&&"
543  ;
544 
545  test_primary =
546  (
547  lit('(')
548  >> test_expr [phx::bind(&insert_test_expr, ql::_val, ql::_1)]
549  >> lit(')')
550  )
551  |
552  (
553  key [ ql::_a = ql::_1 ]
554  >> lit('(')
555  >> - values [ ql::_b = ql::_1 ]
556  >> lit(')') [ phx::bind(&insert_test_func, ql::_val, ql::_a, ql::_b) ]
557  >> -( compare_op [ ql::_c = ql::_1 ]
558  >> value [ phx::bind( &insert_test_compare_op
559  , ql::_val, ql::_c, ql::_1 ) ]
560  )
561  )
562  ;
563 
564  values = ( value % ',' )
565  ;
566 
567  value = ( int_ [ ql::_val = ql::_1 ] >> ! char_(".eE") )
568  | double_ [ ql::_val = ql::_1 ]
569  | bool_ [ ql::_val = ql::_1 ]
570  | str [ ql::_val = ql::_1 ]
571  ;
572 
573  keywords = no_case["AND"] | no_case["OR"]
574  ;
575 
576  key = qi::lexeme[char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")]
577  - keywords
578  ;
579 
580  str = qi::lexeme['\'' >> +(char_ - '\'') >> '\'']
581  ;
582 
583  compare_op = lit("==") [ ql::_val = CO_E ]
584  | lit("!=") [ ql::_val = CO_NE ]
585  | lit("<=") [ ql::_val = CO_LE ]
586  | lit(">=") [ ql::_val = CO_GE ]
587  | lit("<" ) [ ql::_val = CO_L ]
588  | lit(">" ) [ ql::_val = CO_G ]
589  ;
590 
591 
592 }
593 
594 
595 // ------------------------------------------------------------------
596 
597 bool
598  novadaq::errorhandler::parse_condition_test ( std::string const & s
599  , ma_cond_test_expr & expr )
600 {
601  typedef std::string::const_iterator iter_t;
602  typedef ascii::space_type ws_t;
603 
604  if( s.empty() ) return true;
605 
606  cond_test_expr_parser<iter_t, ws_t> test_p;
607 
608  iter_t begin = s.begin();
609  iter_t const end = s.end();
610 
611  bool b = qi::phrase_parse ( begin, end , test_p , space , expr )
612  && begin == end;
613 
614  return b;
615 }
616 
617 
618 
619 
620 
621 
622