Line data Source code
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;
62 : using novadaq::errorhandler::ma_boolean_andexpr;
63 : using novadaq::errorhandler::ma_boolean_cond;
64 : using novadaq::errorhandler::ma_boolean_expr;
65 : using novadaq::errorhandler::ma_cond_test_andexpr;
66 : using novadaq::errorhandler::ma_cond_test_expr;
67 : using novadaq::errorhandler::ma_cond_test_primary;
68 : using novadaq::errorhandler::ma_condition;
69 : using novadaq::errorhandler::ma_domain_andexpr;
70 : using novadaq::errorhandler::ma_domain_cond;
71 : using novadaq::errorhandler::ma_domain_expr;
72 : using novadaq::errorhandler::ma_rule;
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>
82 : struct domain_expr_parser;
83 :
84 : template<class FwdIter, class Skip>
85 : struct boolean_expr_parser;
86 :
87 : template<class FwdIter, class Skip>
88 : struct cond_test_expr_parser;
89 :
90 : class ma_rule;
91 : } // namespace errorhandler
92 : } // namespace novadaq
93 :
94 : // ------------------------------------------------------------------
95 :
96 : static void
97 0 : insert_domain_andexpr(ma_domain_expr& expr, ma_domain_andexpr const& andexpr)
98 : {
99 0 : expr.insert_andexpr(andexpr);
100 0 : }
101 :
102 : static void
103 0 : insert_domain_cond(ma_domain_andexpr& andexpr, ma_domain_cond const& cond)
104 : {
105 0 : andexpr.insert_cond(cond);
106 0 : }
107 :
108 : static void
109 0 : insert_domain_expr(ma_domain_cond& cond, ma_domain_expr const& expr)
110 : {
111 0 : cond.insert_expr(expr);
112 0 : }
113 :
114 : static void
115 0 : insert_cond_arg(ma_domain_cond& cond, std::string const& name, char arg, ma_rule* rule)
116 : {
117 : // update condition's notification list
118 0 : rule->update_notify_list(name, (arg == 's') ? SOURCE : TARGET);
119 :
120 : // push the condition ptr into domain_cond
121 0 : cond.insert_cond_arg(rule->get_cond_idx(name), (arg == 's') ? SOURCE : TARGET, rule->get_cond_size());
122 0 : }
123 :
124 : static void
125 0 : insert_str_cond(ma_domain_cond& cond, std::string const& str)
126 : {
127 0 : cond.insert_str_cond(str);
128 0 : }
129 :
130 : // ------------------------------------------------------------------
131 :
132 : template<class FwdIter, class Skip>
133 : struct novadaq::errorhandler::domain_expr_parser
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>
152 0 : novadaq::errorhandler::domain_expr_parser<FwdIter, Skip>::domain_expr_parser(ma_rule* rule)
153 0 : : domain_expr_parser::base_type(domain_expr)
154 : {
155 0 : domain_expr =
156 0 : domain_andexpr[phx::bind(&insert_domain_andexpr, ql::_val, ql::_1)] % "OR";
157 :
158 0 : domain_andexpr =
159 0 : domain_cond[phx::bind(&insert_domain_cond, ql::_val, ql::_1)] % "AND";
160 :
161 0 : domain_cond =
162 0 : (lit('(') >> domain_expr[phx::bind(&insert_domain_expr, ql::_val, ql::_1)] >> lit(')')) // '(' >> expr >> ')'
163 0 : |
164 : ((
165 : (
166 0 : key[ql::_a = ql::_1] >> ".$" >> char_("st")
167 0 : [phx::bind(&insert_cond_arg, ql::_val, ql::_a, ql::_1, rule)]) %
168 0 : '=') >>
169 0 : -('=' >> (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 0 : keywords = no_case["AND"] | no_case["OR"] | no_case["ANY"];
174 :
175 0 : key = qi::lexeme[char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")] - keywords;
176 : ;
177 :
178 0 : str = qi::lexeme['\'' >> +(ascii::char_ - '\'') >> '\''];
179 0 : }
180 :
181 : // ------------------------------------------------------------------
182 :
183 : static void
184 0 : insert_boolean_andexpr(ma_boolean_expr& expr, ma_boolean_andexpr const& andexpr)
185 : {
186 0 : expr.insert(andexpr);
187 0 : }
188 :
189 : static void
190 0 : insert_boolean_cond(ma_boolean_andexpr& andexpr, ma_boolean_cond const& cond)
191 : {
192 0 : andexpr.insert(cond);
193 0 : }
194 :
195 : static void
196 0 : insert_boolean_expr(ma_boolean_cond& cond, ma_boolean_expr const& expr)
197 : {
198 0 : cond.insert_expr(expr);
199 0 : }
200 :
201 : static void
202 0 : 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 0 : cond.insert_cond(rule->insert_condition_ptr(name, true));
210 0 : }
211 :
212 : static void
213 0 : 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 0 : 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 0 : }
217 :
218 : static void
219 0 : insert_compare_op_double(ma_boolean_cond& cond, compare_op_t op, double rhv)
220 : {
221 0 : cond.insert_compare_op_double(op, rhv);
222 0 : }
223 :
224 : static void
225 0 : insert_compare_op_bool(ma_boolean_cond& cond, compare_op_t op, bool rhv)
226 : {
227 0 : if ((op != CO_E) && (op != CO_NE))
228 0 : throw std::runtime_error("error in parsing rule: booleans can only use == or !=");
229 :
230 0 : cond.insert_compare_op_bool(op, rhv);
231 0 : }
232 :
233 : static void
234 0 : insert_compare_op_string(ma_boolean_cond& cond, compare_op_t op, std::string rhv)
235 : {
236 0 : cond.insert_compare_op_string(op, rhv);
237 0 : }
238 :
239 : // ------------------------------------------------------------------
240 :
241 : using boost::any;
242 : typedef std::vector<any> anys;
243 :
244 : template<class FwdIter, class Skip>
245 : struct novadaq::errorhandler::boolean_expr_parser
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>
268 0 : novadaq::errorhandler::boolean_expr_parser<FwdIter, Skip>::boolean_expr_parser(ma_rule* rule)
269 0 : : boolean_expr_parser::base_type(boolean_expr)
270 : {
271 0 : boolean_expr =
272 0 : boolean_andexpr[phx::bind(&insert_boolean_andexpr, ql::_val, ql::_1)] % "||";
273 :
274 0 : boolean_andexpr =
275 0 : boolean_cond[phx::bind(&insert_boolean_cond, ql::_val, ql::_1)] % "&&";
276 :
277 0 : boolean_cond =
278 0 : (lit('(') >> boolean_expr[phx::bind(&insert_boolean_expr, ql::_val, ql::_1)] >> ')') // '(' >> expr >> ')'
279 0 : |
280 0 : (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 0 : >> -(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 0 : |
284 0 : key[phx::bind(&insert_primitive_cond, ql::_val, ql::_1, rule)]
285 : // Cond
286 : ;
287 :
288 0 : args = (arg % ',');
289 :
290 0 : arg = double_[ql::_val = ql::_1] | bool_[ql::_val = ql::_1] | str[ql::_val = ql::_1];
291 :
292 0 : keywords = no_case["AND"] | no_case["OR"];
293 :
294 0 : key = qi::lexeme[char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")] - keywords;
295 :
296 0 : str = qi::lexeme['\'' >> +(char_ - '\'') >> '\''];
297 :
298 0 : 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 0 : }
300 :
301 : // ------------------------------------------------------------------
302 :
303 : static void
304 0 : set_boolean_expr(ma_boolean_expr& expr, ma_rule* rule)
305 : {
306 0 : rule->set_boolean_expr(expr);
307 0 : }
308 :
309 : static void
310 0 : set_domain_expr(ma_domain_expr& expr, ma_rule* rule)
311 : {
312 0 : rule->set_domain_expr(expr);
313 0 : }
314 :
315 : // ------------------------------------------------------------------
316 :
317 0 : 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 0 : boolean_expr_parser<iter_t, ws_t> boolean_p(rule);
323 0 : domain_expr_parser<iter_t, ws_t> domain_p(rule);
324 :
325 0 : iter_t begin = s.begin();
326 0 : iter_t const end = s.end();
327 :
328 0 : bool b = qi::phrase_parse(
329 0 : 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 0 : begin == end;
331 :
332 0 : return b;
333 0 : }
334 :
335 : // ------------------------------------------------------------------
336 : // Condition test expression parser
337 : // ------------------------------------------------------------------
338 :
339 : static void
340 0 : insert_test_primary(ma_cond_test_andexpr& andexpr, ma_cond_test_primary const& primary)
341 : {
342 0 : andexpr.insert(primary);
343 0 : }
344 :
345 : static void
346 0 : insert_test_andexpr(ma_cond_test_expr& expr, ma_cond_test_andexpr const& andexpr)
347 : {
348 0 : expr.insert(andexpr);
349 0 : }
350 :
351 : static void
352 0 : insert_test_expr(ma_cond_test_primary& primary, ma_cond_test_expr const& expr)
353 : {
354 0 : primary.insert_expr(expr);
355 0 : }
356 :
357 : static void
358 0 : insert_test_func(ma_cond_test_primary& primary, std::string const& function, std::vector<boost::any> const& func_args)
359 : {
360 0 : primary.insert_func(function, func_args);
361 0 : }
362 :
363 : static void
364 0 : insert_test_compare_op(ma_cond_test_primary& primary, compare_op_t op, boost::any const& rhv)
365 : {
366 0 : primary.insert_compare_op(op, rhv);
367 0 : }
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>
378 : struct novadaq::errorhandler::cond_test_expr_parser
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>
403 0 : novadaq::errorhandler::cond_test_expr_parser<FwdIter, Skip>::cond_test_expr_parser()
404 0 : : cond_test_expr_parser::base_type(test_expr)
405 : {
406 0 : test_expr =
407 0 : test_andexpr[phx::bind(&insert_test_andexpr, ql::_val, ql::_1)] % "||";
408 :
409 0 : test_andexpr =
410 0 : test_primary[phx::bind(&insert_test_primary, ql::_val, ql::_1)] % "&&";
411 :
412 0 : test_primary =
413 0 : (lit('(') >> test_expr[phx::bind(&insert_test_expr, ql::_val, ql::_1)] >> lit(')')) |
414 0 : (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 0 : values = (value % ',');
417 :
418 0 : 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 0 : keywords = no_case["AND"] | no_case["OR"];
421 :
422 0 : key = qi::lexeme[char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")] - keywords;
423 :
424 0 : str = qi::lexeme['\'' >> +(char_ - '\'') >> '\''];
425 :
426 0 : 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 0 : }
428 :
429 : // ------------------------------------------------------------------
430 :
431 0 : 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 0 : if (s.empty()) return true;
437 :
438 0 : cond_test_expr_parser<iter_t, ws_t> test_p;
439 :
440 0 : iter_t begin = s.begin();
441 0 : iter_t const end = s.end();
442 :
443 0 : bool b = qi::phrase_parse(begin, end, test_p, space, expr) && begin == end;
444 :
445 0 : return b;
446 0 : }
|