Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-08-17 23:10:25

0001 #ifndef CommonTools_Utils_Grammar_h
0002 #define CommonTools_Utils_Grammar_h
0003 /* \class reco::parser::Grammar
0004  *
0005  * parser grammar
0006  *
0007  * \author original version: Chris Jones, Cornell, 
0008  *         extended by Luca Lista, INFN
0009  *
0010  * \version $Revision: 1.13 $
0011  *
0012  */
0013 #include "boost/spirit/include/classic_core.hpp"
0014 #include "boost/spirit/include/classic_grammar_def.hpp"
0015 #include "boost/spirit/include/classic_chset.hpp"
0016 #include <functional>
0017 #include "CommonTools/Utils/interface/ExpressionNumberSetter.h"
0018 #include "CommonTools/Utils/interface/ExpressionVarSetter.h"
0019 #include "CommonTools/Utils/interface/ExpressionFunctionSetter.h"
0020 #include "CommonTools/Utils/interface/ExpressionConditionSetter.h"
0021 #include "CommonTools/Utils/interface/ComparisonSetter.h"
0022 #include "CommonTools/Utils/interface/BinarySelectorSetter.h"
0023 #include "CommonTools/Utils/interface/TrinarySelectorSetter.h"
0024 #include "CommonTools/Utils/interface/IntSetter.h"
0025 #include "CommonTools/Utils/interface/MethodStack.h"
0026 #include "CommonTools/Utils/interface/MethodArgumentStack.h"
0027 #include "CommonTools/Utils/interface/TypeStack.h"
0028 #include "CommonTools/Utils/interface/IntStack.h"
0029 #include "CommonTools/Utils/interface/FunctionSetter.h"
0030 #include "CommonTools/Utils/interface/CutSetter.h"
0031 #include "CommonTools/Utils/interface/BinaryCutSetter.h"
0032 #include "CommonTools/Utils/interface/UnaryCutSetter.h"
0033 #include "CommonTools/Utils/interface/ExpressionSetter.h"
0034 #include "CommonTools/Utils/interface/ExpressionBinaryOperatorSetter.h"
0035 #include "CommonTools/Utils/interface/ExpressionUnaryOperatorSetter.h"
0036 #include "CommonTools/Utils/interface/ExpressionSelectorSetter.h"
0037 #include "CommonTools/Utils/interface/MethodSetter.h"
0038 #include "CommonTools/Utils/interface/MethodArgumentSetter.h"
0039 #include "CommonTools/Utils/interface/Exception.h"
0040 #include "FWCore/Reflection/interface/TypeWithDict.h"
0041 
0042 namespace reco {
0043   namespace parser {
0044     struct Grammar : public boost::spirit::classic::grammar<Grammar> {
0045       SelectorPtr dummySel_;
0046       ExpressionPtr dummyExpr_;
0047       SelectorPtr* sel_;
0048       ExpressionPtr* expr_;
0049       bool lazy_;
0050       mutable ExpressionStack exprStack;
0051       mutable ComparisonStack cmpStack;
0052       mutable SelectorStack selStack;
0053       mutable FunctionStack funStack, finalFunStack;
0054       mutable MethodStack methStack;
0055       mutable LazyMethodStack lazyMethStack;
0056       mutable MethodArgumentStack methArgStack;
0057       mutable TypeStack typeStack;
0058       mutable IntStack intStack;
0059 
0060       Grammar(SelectorPtr& sel, const edm::TypeWithDict& iType, bool lazy = false)
0061           : sel_(&sel), expr_(&dummyExpr_), lazy_(lazy) {
0062         typeStack.push_back(iType);
0063       }
0064 
0065       Grammar(ExpressionPtr& expr, const edm::TypeWithDict& iType, bool lazy = false)
0066           : sel_(&dummySel_), expr_(&expr), lazy_(lazy) {
0067         typeStack.push_back(iType);
0068       }
0069 
0070       template <typename ScannerT>
0071       struct definition : public boost::spirit::classic::grammar_def<boost::spirit::classic::rule<ScannerT>,
0072                                                                      boost::spirit::classic::same,
0073                                                                      boost::spirit::classic::same> {
0074         typedef boost::spirit::classic::rule<ScannerT> rule;
0075         rule number, var, arrayAccess, metharg, method, term, power, factor, function1, function2, function4,
0076             expression, comparison_op, binary_comp, trinary_comp, logical_combiner, logical_expression,
0077             nocond_expression, cond_expression, logical_factor, logical_term, or_op, and_op, cut, fun;
0078         definition(const Grammar& self) {
0079           using namespace boost::spirit::classic;
0080           using namespace std;
0081 
0082           ExpressionNumberSetter number_s(self.exprStack);
0083           IntSetter int_s(self.intStack);
0084           ExpressionVarSetter var_s(self.exprStack, self.methStack, self.lazyMethStack, self.typeStack);
0085           ExpressionConditionSetter cond_s(self.exprStack, self.selStack);
0086           MethodArgumentSetter methodArg_s(self.methArgStack);
0087           MethodSetter method_s(self.methStack, self.lazyMethStack, self.typeStack, self.methArgStack, self.lazy_);
0088           ComparisonSetter<less_equal<double> > less_equal_s(self.cmpStack);
0089           ComparisonSetter<less<double> > less_s(self.cmpStack);
0090           ComparisonSetter<equal_to<double> > equal_to_s(self.cmpStack);
0091           ComparisonSetter<greater_equal<double> > greater_equal_s(self.cmpStack);
0092           ComparisonSetter<greater<double> > greater_s(self.cmpStack);
0093           ComparisonSetter<not_equal_to<double> > not_equal_to_s(self.cmpStack);
0094           FunctionSetter abs_s(kAbs, self.funStack), acos_s(kAcos, self.funStack), asin_s(kAsin, self.funStack),
0095               atan2_s(kAtan, self.funStack), atan_s(kAtan, self.funStack), chi2prob_s(kChi2Prob, self.funStack),
0096               cosh_s(kCosh, self.funStack), cos_s(kCos, self.funStack), exp_s(kExp, self.funStack),
0097               hypot_s(kHypot, self.funStack), log_s(kLog, self.funStack), log10_s(kLog10, self.funStack),
0098               max_s(kMax, self.funStack), min_s(kMin, self.funStack), pow_s(kPow, self.funStack),
0099               sinh_s(kSinh, self.funStack), sin_s(kSin, self.funStack), sqrt_s(kSqrt, self.funStack),
0100               tanh_s(kTanh, self.funStack), tan_s(kTan, self.funStack), deltaPhi_s(kDeltaPhi, self.funStack),
0101               deltaR_s(kDeltaR, self.funStack), test_bit_s(kTestBit, self.funStack);
0102           FunctionSetterCommit funOk_s(self.funStack, self.finalFunStack);
0103           TrinarySelectorSetter trinary_s(self.selStack, self.cmpStack, self.exprStack);
0104           BinarySelectorSetter binary_s(self.selStack, self.cmpStack, self.exprStack);
0105           ExpressionSelectorSetter expr_sel_s(self.selStack, self.exprStack);
0106           BinaryCutSetter<logical_and<bool> > and_s(self.selStack);
0107           BinaryCutSetter<logical_or<bool> > or_s(self.selStack);
0108           UnaryCutSetter<logical_not<bool> > not_s(self.selStack);
0109           CutSetter cut_s(*self.sel_, self.selStack);
0110           ExpressionSetter expr_s(*self.expr_, self.exprStack);
0111           ExpressionBinaryOperatorSetter<plus<double> > plus_s(self.exprStack);
0112           ExpressionBinaryOperatorSetter<minus<double> > minus_s(self.exprStack);
0113           ExpressionBinaryOperatorSetter<multiplies<double> > multiplies_s(self.exprStack);
0114           ExpressionBinaryOperatorSetter<divides<double> > divides_s(self.exprStack);
0115           ExpressionBinaryOperatorSetter<power_of<double> > power_of_s(self.exprStack);
0116           ExpressionUnaryOperatorSetter<negate<double> > negate_s(self.exprStack);
0117           ExpressionFunctionSetter fun_s(self.exprStack, self.finalFunStack);
0118           //      Abort abort_s;
0119           BOOST_SPIRIT_DEBUG_RULE(var);
0120           BOOST_SPIRIT_DEBUG_RULE(arrayAccess);
0121           BOOST_SPIRIT_DEBUG_RULE(method);
0122           BOOST_SPIRIT_DEBUG_RULE(logical_expression);
0123           BOOST_SPIRIT_DEBUG_RULE(cond_expression);
0124           BOOST_SPIRIT_DEBUG_RULE(logical_term);
0125           BOOST_SPIRIT_DEBUG_RULE(logical_factor);
0126           BOOST_SPIRIT_DEBUG_RULE(number);
0127           BOOST_SPIRIT_DEBUG_RULE(metharg);
0128           BOOST_SPIRIT_DEBUG_RULE(function1);
0129           BOOST_SPIRIT_DEBUG_RULE(function2);
0130           BOOST_SPIRIT_DEBUG_RULE(function4);
0131           BOOST_SPIRIT_DEBUG_RULE(expression);
0132           BOOST_SPIRIT_DEBUG_RULE(term);
0133           BOOST_SPIRIT_DEBUG_RULE(power);
0134           BOOST_SPIRIT_DEBUG_RULE(factor);
0135           BOOST_SPIRIT_DEBUG_RULE(or_op);
0136           BOOST_SPIRIT_DEBUG_RULE(and_op);
0137           BOOST_SPIRIT_DEBUG_RULE(comparison_op);
0138           BOOST_SPIRIT_DEBUG_RULE(binary_comp);
0139           BOOST_SPIRIT_DEBUG_RULE(trinary_comp);
0140           BOOST_SPIRIT_DEBUG_RULE(cut);
0141           BOOST_SPIRIT_DEBUG_RULE(fun);
0142 
0143           boost::spirit::classic::assertion<SyntaxErrors> expectParenthesis(kMissingClosingParenthesis);
0144           boost::spirit::classic::assertion<SyntaxErrors> expect(kSyntaxError);
0145 
0146           number = real_p[number_s];
0147           metharg = (strict_real_p[methodArg_s]) | (int_p[methodArg_s]) |
0148                     (ch_p('"') >> *(~ch_p('"')) >> ch_p('"'))[methodArg_s] |
0149                     (ch_p('\'') >> *(~ch_p('\'')) >> ch_p('\''))[methodArg_s];
0150           var =  // alnum_p doesn't accept underscores, so we use chset<>; lexeme_d needed to avoid whitespace skipping within method names
0151               (lexeme_d[alpha_p >> *chset<>("a-zA-Z0-9_")] >> ch_p('(') >> metharg >> *(ch_p(',') >> metharg) >>
0152                expectParenthesis(ch_p(')')))[method_s] |
0153               ((lexeme_d[alpha_p >> *chset<>("a-zA-Z0-9_")])[method_s] >> !(ch_p('(') >> ch_p(')')));
0154           arrayAccess = (ch_p('[') >> metharg >> *(ch_p(',') >> metharg) >> expectParenthesis(ch_p(']')))[method_s];
0155           method = (var >> *(arrayAccess | (ch_p('.') >> expect(var))))[var_s];
0156           function1 = chseq_p("abs")[abs_s] | chseq_p("acos")[acos_s] | chseq_p("asin")[asin_s] |
0157                       chseq_p("atan")[atan_s] | chseq_p("cosh")[cosh_s] | chseq_p("cos")[cos_s] |
0158                       chseq_p("exp")[exp_s] | chseq_p("log")[log_s] | chseq_p("log10")[log10_s] |
0159                       chseq_p("sinh")[sinh_s] | chseq_p("sin")[sin_s] | chseq_p("sqrt")[sqrt_s] |
0160                       chseq_p("tanh")[tanh_s] | chseq_p("tan")[tan_s];
0161           function2 = chseq_p("atan2")[atan2_s] | chseq_p("chi2prob")[chi2prob_s] | chseq_p("pow")[pow_s] |
0162                       chseq_p("min")[min_s] | chseq_p("max")[max_s] | chseq_p("deltaPhi")[deltaPhi_s] |
0163                       chseq_p("hypot")[hypot_s] | chseq_p("test_bit")[test_bit_s];
0164           function4 = chseq_p("deltaR")[deltaR_s];
0165           expression = cond_expression | nocond_expression;
0166           nocond_expression = term >> (*(('+' >> expect(term))[plus_s] | ('-' >> expect(term))[minus_s]));
0167           cond_expression = (ch_p('?') >> logical_expression >> ch_p('?') >> expect(expression) >> ch_p(":") >>
0168                              expect(expression))[cond_s];
0169           term = power >> *(('*' >> expect(power))[multiplies_s] | ('/' >> expect(power))[divides_s]);
0170           power = factor >> *(('^' >> expect(factor))[power_of_s]);
0171           factor =
0172               number | (function1 >> ch_p('(')[funOk_s] >> expect(expression) >> expectParenthesis(ch_p(')')))[fun_s] |
0173               (function2 >> ch_p('(')[funOk_s] >> expect(expression) >> expect(ch_p(',')) >> expect(expression) >>
0174                expectParenthesis(ch_p(')')))[fun_s] |
0175               (function4 >> ch_p('(')[funOk_s] >> expect(expression) >> expect(ch_p(',')) >> expect(expression) >>
0176                expect(ch_p(',')) >> expect(expression) >> expect(ch_p(',')) >> expect(expression) >>
0177                expectParenthesis(ch_p(')')))[fun_s] |
0178               //NOTE: no expect around the first ch_p('(') otherwise it can't parse a method that starts like a function name (i.e. maxSomething)
0179               method |
0180               //NOTE: no 'expectedParenthesis around ending ')' because at this point the partial phrase
0181               //       "(a"
0182               //could refer to an expression, e.g., "(a+b)*c" or a logical expression "(a<1) &&"
0183               //so we need to allow the parser to 'backup' and try a different approach.
0184               //NOTE: if the parser were changed so a logical expression could be used as an expression,e.g.
0185               //  (a<b)+1 <2
0186               // then we could remove such an ambiguity.
0187               ch_p('(') >> expression >> ch_p(')') | (ch_p('-') >> factor)[negate_s] | (ch_p('+') >> factor);
0188           comparison_op = (ch_p('<') >> ch_p('=')[less_equal_s]) | (ch_p('<')[less_s]) |
0189                           (ch_p('=') >> ch_p('=')[equal_to_s]) | (ch_p('=')[equal_to_s]) |
0190                           (ch_p('>') >> ch_p('=')[greater_equal_s]) | (ch_p('>')[greater_s]) |
0191                           (ch_p('!') >> ch_p('=')[not_equal_to_s]);
0192           binary_comp = (expression >> comparison_op >> expect(expression))[binary_s];
0193           trinary_comp =
0194               (expression >> comparison_op >> expect(expression) >> comparison_op >> expect(expression))[trinary_s];
0195           or_op = ch_p('|') >> ch_p('|') | ch_p('|');
0196           and_op = ch_p('&') >> ch_p('&') | ch_p('&');
0197           logical_expression = logical_term >> *(or_op >> expect(logical_term))[or_s];
0198           logical_term = logical_factor >> *(and_op >> expect(logical_factor))[and_s];
0199           logical_factor = trinary_comp | binary_comp |
0200                            ch_p('(') >> logical_expression >> expectParenthesis(ch_p(')')) |
0201                            (ch_p('!') >> expect(logical_factor))[not_s] | expression[expr_sel_s];
0202           ;
0203           cut = logical_expression[cut_s];
0204           fun = expression[expr_s];
0205           this->start_parsers(cut, fun);
0206         }
0207       };
0208     };
0209   }  // namespace parser
0210 }  // namespace reco
0211 
0212 #endif