Grammar

definition

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
#ifndef CommonTools_Utils_Grammar_h
#define CommonTools_Utils_Grammar_h
/* \class reco::parser::Grammar
 *
 * parser grammar
 *
 * \author original version: Chris Jones, Cornell, 
 *         extended by Luca Lista, INFN
 *
 * \version $Revision: 1.13 $
 *
 */
#include "boost/spirit/include/classic_core.hpp"
#include "boost/spirit/include/classic_grammar_def.hpp"
#include "boost/spirit/include/classic_chset.hpp"
#include <functional>
#include "CommonTools/Utils/interface/parser/ExpressionNumberSetter.h"
#include "CommonTools/Utils/interface/parser/ExpressionVarSetter.h"
#include "CommonTools/Utils/interface/parser/ExpressionFunctionSetter.h"
#include "CommonTools/Utils/interface/parser/ExpressionConditionSetter.h"
#include "CommonTools/Utils/interface/parser/ComparisonSetter.h"
#include "CommonTools/Utils/interface/parser/BinarySelectorSetter.h"
#include "CommonTools/Utils/interface/parser/TrinarySelectorSetter.h"
#include "CommonTools/Utils/interface/parser/IntSetter.h"
#include "CommonTools/Utils/interface/parser/MethodStack.h"
#include "CommonTools/Utils/interface/parser/MethodArgumentStack.h"
#include "CommonTools/Utils/interface/parser/TypeStack.h"
#include "CommonTools/Utils/interface/parser/IntStack.h"
#include "CommonTools/Utils/interface/parser/FunctionSetter.h"
#include "CommonTools/Utils/interface/parser/CutSetter.h"
#include "CommonTools/Utils/interface/parser/BinaryCutSetter.h"
#include "CommonTools/Utils/interface/parser/UnaryCutSetter.h"
#include "CommonTools/Utils/interface/parser/ExpressionSetter.h"
#include "CommonTools/Utils/interface/parser/ExpressionBinaryOperatorSetter.h"
#include "CommonTools/Utils/interface/parser/ExpressionUnaryOperatorSetter.h"
#include "CommonTools/Utils/interface/parser/ExpressionSelectorSetter.h"
#include "CommonTools/Utils/interface/parser/MethodSetter.h"
#include "CommonTools/Utils/interface/parser/MethodArgumentSetter.h"
#include "CommonTools/Utils/interface/parser/Exception.h"
#include "FWCore/Reflection/interface/TypeWithDict.h"

namespace reco {
  namespace parser {
    struct Grammar : public boost::spirit::classic::grammar<Grammar> {
      SelectorPtr dummySel_;
      ExpressionPtr dummyExpr_;
      SelectorPtr* sel_;
      ExpressionPtr* expr_;
      bool lazy_;
      mutable ExpressionStack exprStack;
      mutable ComparisonStack cmpStack;
      mutable SelectorStack selStack;
      mutable FunctionStack funStack, finalFunStack;
      mutable MethodStack methStack;
      mutable LazyMethodStack lazyMethStack;
      mutable MethodArgumentStack methArgStack;
      mutable TypeStack typeStack;
      mutable IntStack intStack;

      Grammar(SelectorPtr& sel, const edm::TypeWithDict& iType, bool lazy = false)
          : sel_(&sel), expr_(&dummyExpr_), lazy_(lazy) {
        typeStack.push_back(iType);
      }

      Grammar(ExpressionPtr& expr, const edm::TypeWithDict& iType, bool lazy = false)
          : sel_(&dummySel_), expr_(&expr), lazy_(lazy) {
        typeStack.push_back(iType);
      }

      template <typename ScannerT>
      struct definition : public boost::spirit::classic::grammar_def<boost::spirit::classic::rule<ScannerT>,
                                                                     boost::spirit::classic::same,
                                                                     boost::spirit::classic::same> {
        typedef boost::spirit::classic::rule<ScannerT> rule;
        rule number, var, arrayAccess, metharg, method, term, power, factor, function1, function2, function4,
            expression, comparison_op, binary_comp, trinary_comp, logical_combiner, logical_expression,
            nocond_expression, cond_expression, logical_factor, logical_term, or_op, and_op, cut, fun;
        definition(const Grammar& self) {
          using namespace boost::spirit::classic;
          using namespace std;

          ExpressionNumberSetter number_s(self.exprStack);
          IntSetter int_s(self.intStack);
          ExpressionVarSetter var_s(self.exprStack, self.methStack, self.lazyMethStack, self.typeStack);
          ExpressionConditionSetter cond_s(self.exprStack, self.selStack);
          MethodArgumentSetter methodArg_s(self.methArgStack);
          MethodSetter method_s(self.methStack, self.lazyMethStack, self.typeStack, self.methArgStack, self.lazy_);
          ComparisonSetter<less_equal<double> > less_equal_s(self.cmpStack);
          ComparisonSetter<less<double> > less_s(self.cmpStack);
          ComparisonSetter<equal_to<double> > equal_to_s(self.cmpStack);
          ComparisonSetter<greater_equal<double> > greater_equal_s(self.cmpStack);
          ComparisonSetter<greater<double> > greater_s(self.cmpStack);
          ComparisonSetter<not_equal_to<double> > not_equal_to_s(self.cmpStack);
          FunctionSetter abs_s(kAbs, self.funStack), acos_s(kAcos, self.funStack), asin_s(kAsin, self.funStack),
              atan2_s(kAtan, self.funStack), atan_s(kAtan, self.funStack), chi2prob_s(kChi2Prob, self.funStack),
              cosh_s(kCosh, self.funStack), cos_s(kCos, self.funStack), exp_s(kExp, self.funStack),
              hypot_s(kHypot, self.funStack), log_s(kLog, self.funStack), log10_s(kLog10, self.funStack),
              max_s(kMax, self.funStack), min_s(kMin, self.funStack), pow_s(kPow, self.funStack),
              sinh_s(kSinh, self.funStack), sin_s(kSin, self.funStack), sqrt_s(kSqrt, self.funStack),
              tanh_s(kTanh, self.funStack), tan_s(kTan, self.funStack), deltaPhi_s(kDeltaPhi, self.funStack),
              deltaR_s(kDeltaR, self.funStack), test_bit_s(kTestBit, self.funStack);
          FunctionSetterCommit funOk_s(self.funStack, self.finalFunStack);
          TrinarySelectorSetter trinary_s(self.selStack, self.cmpStack, self.exprStack);
          BinarySelectorSetter binary_s(self.selStack, self.cmpStack, self.exprStack);
          ExpressionSelectorSetter expr_sel_s(self.selStack, self.exprStack);
          BinaryCutSetter<logical_and<bool> > and_s(self.selStack);
          BinaryCutSetter<logical_or<bool> > or_s(self.selStack);
          UnaryCutSetter<logical_not<bool> > not_s(self.selStack);
          CutSetter cut_s(*self.sel_, self.selStack);
          ExpressionSetter expr_s(*self.expr_, self.exprStack);
          ExpressionBinaryOperatorSetter<plus<double> > plus_s(self.exprStack);
          ExpressionBinaryOperatorSetter<minus<double> > minus_s(self.exprStack);
          ExpressionBinaryOperatorSetter<multiplies<double> > multiplies_s(self.exprStack);
          ExpressionBinaryOperatorSetter<divides<double> > divides_s(self.exprStack);
          ExpressionBinaryOperatorSetter<int_div_remainder<double> > remainder_s(self.exprStack);
          ExpressionBinaryOperatorSetter<power_of<double> > power_of_s(self.exprStack);
          ExpressionUnaryOperatorSetter<negate<double> > negate_s(self.exprStack);
          ExpressionFunctionSetter fun_s(self.exprStack, self.finalFunStack);
          //	  Abort abort_s;
          BOOST_SPIRIT_DEBUG_RULE(var);
          BOOST_SPIRIT_DEBUG_RULE(arrayAccess);
          BOOST_SPIRIT_DEBUG_RULE(method);
          BOOST_SPIRIT_DEBUG_RULE(logical_expression);
          BOOST_SPIRIT_DEBUG_RULE(cond_expression);
          BOOST_SPIRIT_DEBUG_RULE(logical_term);
          BOOST_SPIRIT_DEBUG_RULE(logical_factor);
          BOOST_SPIRIT_DEBUG_RULE(number);
          BOOST_SPIRIT_DEBUG_RULE(metharg);
          BOOST_SPIRIT_DEBUG_RULE(function1);
          BOOST_SPIRIT_DEBUG_RULE(function2);
          BOOST_SPIRIT_DEBUG_RULE(function4);
          BOOST_SPIRIT_DEBUG_RULE(expression);
          BOOST_SPIRIT_DEBUG_RULE(term);
          BOOST_SPIRIT_DEBUG_RULE(power);
          BOOST_SPIRIT_DEBUG_RULE(factor);
          BOOST_SPIRIT_DEBUG_RULE(or_op);
          BOOST_SPIRIT_DEBUG_RULE(and_op);
          BOOST_SPIRIT_DEBUG_RULE(comparison_op);
          BOOST_SPIRIT_DEBUG_RULE(binary_comp);
          BOOST_SPIRIT_DEBUG_RULE(trinary_comp);
          BOOST_SPIRIT_DEBUG_RULE(cut);
          BOOST_SPIRIT_DEBUG_RULE(fun);

          boost::spirit::classic::assertion<SyntaxErrors> expectParenthesis(kMissingClosingParenthesis);
          boost::spirit::classic::assertion<SyntaxErrors> expect(kSyntaxError);

          number = real_p[number_s];
          metharg = (strict_real_p[methodArg_s]) | (int_p[methodArg_s]) |
                    (ch_p('"') >> *(~ch_p('"')) >> ch_p('"'))[methodArg_s] |
                    (ch_p('\'') >> *(~ch_p('\'')) >> ch_p('\''))[methodArg_s];
          var =  // alnum_p doesn't accept underscores, so we use chset<>; lexeme_d needed to avoid whitespace skipping within method names
              (lexeme_d[alpha_p >> *chset<>("a-zA-Z0-9_")] >> ch_p('(') >> metharg >> *(ch_p(',') >> metharg) >>
               expectParenthesis(ch_p(')')))[method_s] |
              ((lexeme_d[alpha_p >> *chset<>("a-zA-Z0-9_")])[method_s] >> !(ch_p('(') >> ch_p(')')));
          arrayAccess = (ch_p('[') >> metharg >> *(ch_p(',') >> metharg) >> expectParenthesis(ch_p(']')))[method_s];
          method = (var >> *(arrayAccess | (ch_p('.') >> expect(var))))[var_s];
          function1 = chseq_p("abs")[abs_s] | chseq_p("acos")[acos_s] | chseq_p("asin")[asin_s] |
                      chseq_p("atan")[atan_s] | chseq_p("cosh")[cosh_s] | chseq_p("cos")[cos_s] |
                      chseq_p("exp")[exp_s] | chseq_p("log")[log_s] | chseq_p("log10")[log10_s] |
                      chseq_p("sinh")[sinh_s] | chseq_p("sin")[sin_s] | chseq_p("sqrt")[sqrt_s] |
                      chseq_p("tanh")[tanh_s] | chseq_p("tan")[tan_s];
          function2 = chseq_p("atan2")[atan2_s] | chseq_p("chi2prob")[chi2prob_s] | chseq_p("pow")[pow_s] |
                      chseq_p("min")[min_s] | chseq_p("max")[max_s] | chseq_p("deltaPhi")[deltaPhi_s] |
                      chseq_p("hypot")[hypot_s] | chseq_p("test_bit")[test_bit_s];
          function4 = chseq_p("deltaR")[deltaR_s];
          expression = cond_expression | nocond_expression;
          nocond_expression = term >> (*(('+' >> expect(term))[plus_s] | ('-' >> expect(term))[minus_s]));
          cond_expression = (ch_p('?') >> logical_expression >> ch_p('?') >> expect(expression) >> ch_p(":") >>
                             expect(expression))[cond_s];
          term = power >> *(('*' >> expect(power))[multiplies_s] | ('/' >> expect(power))[divides_s] |
                            ('%' >> expect(power))[remainder_s]);
          power = factor >> *(('^' >> expect(factor))[power_of_s]);
          factor =
              number | (function1 >> ch_p('(')[funOk_s] >> expect(expression) >> expectParenthesis(ch_p(')')))[fun_s] |
              (function2 >> ch_p('(')[funOk_s] >> expect(expression) >> expect(ch_p(',')) >> expect(expression) >>
               expectParenthesis(ch_p(')')))[fun_s] |
              (function4 >> ch_p('(')[funOk_s] >> expect(expression) >> expect(ch_p(',')) >> expect(expression) >>
               expect(ch_p(',')) >> expect(expression) >> expect(ch_p(',')) >> expect(expression) >>
               expectParenthesis(ch_p(')')))[fun_s] |
              //NOTE: no expect around the first ch_p('(') otherwise it can't parse a method that starts like a function name (i.e. maxSomething)
              method |
              //NOTE: no 'expectedParenthesis around ending ')' because at this point the partial phrase
              //       "(a"
              //could refer to an expression, e.g., "(a+b)*c" or a logical expression "(a<1) &&"
              //so we need to allow the parser to 'backup' and try a different approach.
              //NOTE: if the parser were changed so a logical expression could be used as an expression,e.g.
              //  (a<b)+1 <2
              // then we could remove such an ambiguity.
              ch_p('(') >> expression >> ch_p(')') | (ch_p('-') >> factor)[negate_s] | (ch_p('+') >> factor);
          comparison_op = (ch_p('<') >> ch_p('=')[less_equal_s]) | (ch_p('<')[less_s]) |
                          (ch_p('=') >> ch_p('=')[equal_to_s]) | (ch_p('=')[equal_to_s]) |
                          (ch_p('>') >> ch_p('=')[greater_equal_s]) | (ch_p('>')[greater_s]) |
                          (ch_p('!') >> ch_p('=')[not_equal_to_s]);
          binary_comp = (expression >> comparison_op >> expect(expression))[binary_s];
          trinary_comp =
              (expression >> comparison_op >> expect(expression) >> comparison_op >> expect(expression))[trinary_s];
          or_op = ch_p('|') >> ch_p('|') | ch_p('|');
          and_op = ch_p('&') >> ch_p('&') | ch_p('&');
          logical_expression = logical_term >> *(or_op >> expect(logical_term))[or_s];
          logical_term = logical_factor >> *(and_op >> expect(logical_factor))[and_s];
          logical_factor = trinary_comp | binary_comp |
                           ch_p('(') >> logical_expression >> expectParenthesis(ch_p(')')) |
                           (ch_p('!') >> expect(logical_factor))[not_s] | expression[expr_sel_s];
          ;
          cut = logical_expression[cut_s];
          fun = expression[expr_s];
          this->start_parsers(cut, fun);
        }
      };
    };
  }  // namespace parser
}  // namespace reco

#endif