Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:01:17

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/parser/ExpressionNumberSetter.h"
0018 #include "CommonTools/Utils/interface/parser/ExpressionVarSetter.h"
0019 #include "CommonTools/Utils/interface/parser/ExpressionFunctionSetter.h"
0020 #include "CommonTools/Utils/interface/parser/ExpressionConditionSetter.h"
0021 #include "CommonTools/Utils/interface/parser/ComparisonSetter.h"
0022 #include "CommonTools/Utils/interface/parser/BinarySelectorSetter.h"
0023 #include "CommonTools/Utils/interface/parser/TrinarySelectorSetter.h"
0024 #include "CommonTools/Utils/interface/parser/IntSetter.h"
0025 #include "CommonTools/Utils/interface/parser/MethodStack.h"
0026 #include "CommonTools/Utils/interface/parser/MethodArgumentStack.h"
0027 #include "CommonTools/Utils/interface/parser/TypeStack.h"
0028 #include "CommonTools/Utils/interface/parser/IntStack.h"
0029 #include "CommonTools/Utils/interface/parser/FunctionSetter.h"
0030 #include "CommonTools/Utils/interface/parser/CutSetter.h"
0031 #include "CommonTools/Utils/interface/parser/BinaryCutSetter.h"
0032 #include "CommonTools/Utils/interface/parser/UnaryCutSetter.h"
0033 #include "CommonTools/Utils/interface/parser/ExpressionSetter.h"
0034 #include "CommonTools/Utils/interface/parser/ExpressionBinaryOperatorSetter.h"
0035 #include "CommonTools/Utils/interface/parser/ExpressionUnaryOperatorSetter.h"
0036 #include "CommonTools/Utils/interface/parser/ExpressionSelectorSetter.h"
0037 #include "CommonTools/Utils/interface/parser/MethodSetter.h"
0038 #include "CommonTools/Utils/interface/parser/MethodArgumentSetter.h"
0039 #include "CommonTools/Utils/interface/parser/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<int_div_remainder<double> > remainder_s(self.exprStack);
0116           ExpressionBinaryOperatorSetter<power_of<double> > power_of_s(self.exprStack);
0117           ExpressionUnaryOperatorSetter<negate<double> > negate_s(self.exprStack);
0118           ExpressionFunctionSetter fun_s(self.exprStack, self.finalFunStack);
0119           //      Abort abort_s;
0120           BOOST_SPIRIT_DEBUG_RULE(var);
0121           BOOST_SPIRIT_DEBUG_RULE(arrayAccess);
0122           BOOST_SPIRIT_DEBUG_RULE(method);
0123           BOOST_SPIRIT_DEBUG_RULE(logical_expression);
0124           BOOST_SPIRIT_DEBUG_RULE(cond_expression);
0125           BOOST_SPIRIT_DEBUG_RULE(logical_term);
0126           BOOST_SPIRIT_DEBUG_RULE(logical_factor);
0127           BOOST_SPIRIT_DEBUG_RULE(number);
0128           BOOST_SPIRIT_DEBUG_RULE(metharg);
0129           BOOST_SPIRIT_DEBUG_RULE(function1);
0130           BOOST_SPIRIT_DEBUG_RULE(function2);
0131           BOOST_SPIRIT_DEBUG_RULE(function4);
0132           BOOST_SPIRIT_DEBUG_RULE(expression);
0133           BOOST_SPIRIT_DEBUG_RULE(term);
0134           BOOST_SPIRIT_DEBUG_RULE(power);
0135           BOOST_SPIRIT_DEBUG_RULE(factor);
0136           BOOST_SPIRIT_DEBUG_RULE(or_op);
0137           BOOST_SPIRIT_DEBUG_RULE(and_op);
0138           BOOST_SPIRIT_DEBUG_RULE(comparison_op);
0139           BOOST_SPIRIT_DEBUG_RULE(binary_comp);
0140           BOOST_SPIRIT_DEBUG_RULE(trinary_comp);
0141           BOOST_SPIRIT_DEBUG_RULE(cut);
0142           BOOST_SPIRIT_DEBUG_RULE(fun);
0143 
0144           boost::spirit::classic::assertion<SyntaxErrors> expectParenthesis(kMissingClosingParenthesis);
0145           boost::spirit::classic::assertion<SyntaxErrors> expect(kSyntaxError);
0146 
0147           number = real_p[number_s];
0148           metharg = (strict_real_p[methodArg_s]) | (int_p[methodArg_s]) |
0149                     (ch_p('"') >> *(~ch_p('"')) >> ch_p('"'))[methodArg_s] |
0150                     (ch_p('\'') >> *(~ch_p('\'')) >> ch_p('\''))[methodArg_s];
0151           var =  // alnum_p doesn't accept underscores, so we use chset<>; lexeme_d needed to avoid whitespace skipping within method names
0152               (lexeme_d[alpha_p >> *chset<>("a-zA-Z0-9_")] >> ch_p('(') >> metharg >> *(ch_p(',') >> metharg) >>
0153                expectParenthesis(ch_p(')')))[method_s] |
0154               ((lexeme_d[alpha_p >> *chset<>("a-zA-Z0-9_")])[method_s] >> !(ch_p('(') >> ch_p(')')));
0155           arrayAccess = (ch_p('[') >> metharg >> *(ch_p(',') >> metharg) >> expectParenthesis(ch_p(']')))[method_s];
0156           method = (var >> *(arrayAccess | (ch_p('.') >> expect(var))))[var_s];
0157           function1 = chseq_p("abs")[abs_s] | chseq_p("acos")[acos_s] | chseq_p("asin")[asin_s] |
0158                       chseq_p("atan")[atan_s] | chseq_p("cosh")[cosh_s] | chseq_p("cos")[cos_s] |
0159                       chseq_p("exp")[exp_s] | chseq_p("log")[log_s] | chseq_p("log10")[log10_s] |
0160                       chseq_p("sinh")[sinh_s] | chseq_p("sin")[sin_s] | chseq_p("sqrt")[sqrt_s] |
0161                       chseq_p("tanh")[tanh_s] | chseq_p("tan")[tan_s];
0162           function2 = chseq_p("atan2")[atan2_s] | chseq_p("chi2prob")[chi2prob_s] | chseq_p("pow")[pow_s] |
0163                       chseq_p("min")[min_s] | chseq_p("max")[max_s] | chseq_p("deltaPhi")[deltaPhi_s] |
0164                       chseq_p("hypot")[hypot_s] | chseq_p("test_bit")[test_bit_s];
0165           function4 = chseq_p("deltaR")[deltaR_s];
0166           expression = cond_expression | nocond_expression;
0167           nocond_expression = term >> (*(('+' >> expect(term))[plus_s] | ('-' >> expect(term))[minus_s]));
0168           cond_expression = (ch_p('?') >> logical_expression >> ch_p('?') >> expect(expression) >> ch_p(":") >>
0169                              expect(expression))[cond_s];
0170           term = power >> *(('*' >> expect(power))[multiplies_s] | ('/' >> expect(power))[divides_s] |
0171                             ('%' >> expect(power))[remainder_s]);
0172           power = factor >> *(('^' >> expect(factor))[power_of_s]);
0173           factor =
0174               number | (function1 >> ch_p('(')[funOk_s] >> expect(expression) >> expectParenthesis(ch_p(')')))[fun_s] |
0175               (function2 >> ch_p('(')[funOk_s] >> expect(expression) >> expect(ch_p(',')) >> expect(expression) >>
0176                expectParenthesis(ch_p(')')))[fun_s] |
0177               (function4 >> ch_p('(')[funOk_s] >> expect(expression) >> expect(ch_p(',')) >> expect(expression) >>
0178                expect(ch_p(',')) >> expect(expression) >> expect(ch_p(',')) >> expect(expression) >>
0179                expectParenthesis(ch_p(')')))[fun_s] |
0180               //NOTE: no expect around the first ch_p('(') otherwise it can't parse a method that starts like a function name (i.e. maxSomething)
0181               method |
0182               //NOTE: no 'expectedParenthesis around ending ')' because at this point the partial phrase
0183               //       "(a"
0184               //could refer to an expression, e.g., "(a+b)*c" or a logical expression "(a<1) &&"
0185               //so we need to allow the parser to 'backup' and try a different approach.
0186               //NOTE: if the parser were changed so a logical expression could be used as an expression,e.g.
0187               //  (a<b)+1 <2
0188               // then we could remove such an ambiguity.
0189               ch_p('(') >> expression >> ch_p(')') | (ch_p('-') >> factor)[negate_s] | (ch_p('+') >> factor);
0190           comparison_op = (ch_p('<') >> ch_p('=')[less_equal_s]) | (ch_p('<')[less_s]) |
0191                           (ch_p('=') >> ch_p('=')[equal_to_s]) | (ch_p('=')[equal_to_s]) |
0192                           (ch_p('>') >> ch_p('=')[greater_equal_s]) | (ch_p('>')[greater_s]) |
0193                           (ch_p('!') >> ch_p('=')[not_equal_to_s]);
0194           binary_comp = (expression >> comparison_op >> expect(expression))[binary_s];
0195           trinary_comp =
0196               (expression >> comparison_op >> expect(expression) >> comparison_op >> expect(expression))[trinary_s];
0197           or_op = ch_p('|') >> ch_p('|') | ch_p('|');
0198           and_op = ch_p('&') >> ch_p('&') | ch_p('&');
0199           logical_expression = logical_term >> *(or_op >> expect(logical_term))[or_s];
0200           logical_term = logical_factor >> *(and_op >> expect(logical_factor))[and_s];
0201           logical_factor = trinary_comp | binary_comp |
0202                            ch_p('(') >> logical_expression >> expectParenthesis(ch_p(')')) |
0203                            (ch_p('!') >> expect(logical_factor))[not_s] | expression[expr_sel_s];
0204           ;
0205           cut = logical_expression[cut_s];
0206           fun = expression[expr_s];
0207           this->start_parsers(cut, fun);
0208         }
0209       };
0210     };
0211   }  // namespace parser
0212 }  // namespace reco
0213 
0214 #endif