MathExpressionGrammar.h
Go to the documentation of this file.
1 #ifndef _utl_MathExpressionGrammar_h_
2 #define _utl_MathExpressionGrammar_h_
3 
13 #include <utl/SymbolTable.h>
14 #include <utl/ExpressionParser.h>
15 #include <utl/AugerException.h>
16 #include <utl/ErrorLogger.h>
17 
18 //#define BOOST_SPIRIT_DEBUG
19 
20 #include <boost/version.hpp>
21 #if BOOST_VERSION >= 103800
22 # define BOOST_SPIRIT_USE_OLD_NAMESPACE
23 # include <boost/spirit/include/classic.hpp>
24 # include <boost/spirit/include/phoenix1_binders.hpp>
25 # include <boost/spirit/include/phoenix1_functions.hpp>
26 #else
27 # include <boost/spirit.hpp>
28 # include <boost/spirit/phoenix/binders.hpp>
29 # include <boost/spirit/phoenix/primitives.hpp>
30 # include <boost/spirit/phoenix/functions.hpp>
31 #endif
32 
33 #include <string>
34 #include <cmath>
35 //#include <iostream>
36 
37 
38 namespace utl {
39 
40  // RU 14 Jul 2017, to someone smarter than me: convert this to templated solution:
41 #define FIMP_std(name) \
42  struct F_ ## name ## _Impl { \
43  template<typename T1> \
44  struct result { typedef double type; }; \
45  template<typename T1> \
46  T1 operator()(T1& t1) const { return std::name(t1); } \
47  }; \
48  const phoenix::function<F_ ## name ## _Impl> F_ ## name = F_ ## name ## _Impl()
49 
50  FIMP_std(exp);
51  FIMP_std(log10);
52  FIMP_std(log);
53  FIMP_std(sin);
54  FIMP_std(tan);
55  FIMP_std(cos);
56 
57  struct PowerToImpl2 {
58  template<typename T1, typename T2>
59  struct result { typedef double type; };
60  template<typename T1, typename T2>
61  T1 operator()(T1& t1, T2& t2) const { return std::pow(t1, t2); }
62  };
63  // Create it as a constant Phoenix Function
64  const phoenix::function<PowerToImpl2> power2 = PowerToImpl2();
65 
66 
67  // MathExpression Grammar Structure
68  struct MathExpressionGrammar : public boost::spirit::grammar<MathExpressionGrammar> {
69 
71  : fSymbols(&sym), fResult(&result) { }
72 
74  : fSymbols(&sym), fVariables(vars), fResult(&result) { }
75 
76  void SetResult(double& v) const { fResult = const_cast<double*>(&v); }
77 
79  struct SValueClosure : public boost::spirit::closure<SValueClosure, double> {
80  member1 value;
81  };
82 
84  struct SAssignmentClosure : public boost::spirit::closure<SAssignmentClosure, std::string, double> {
85  member1 name;
86  member2 value;
87  };
88 
90  struct SStringClosure : public boost::spirit::closure<SStringClosure, std::string> {
91  member1 name;
92  };
93 
95  template<typename ScannerT>
96  struct definition {
98  {
99  prefix
100  =
101  (
102  ('-' >> multdiv [prefix.value = -phoenix::arg1])
103  | ('+' >> multdiv [prefix.value = phoenix::arg1])
104  )
105  ;
106 
107  term
108  =
109  ('(' >> expression [term.value = phoenix::arg1] >> ')')
110  | prefix [term.value = phoenix::arg1]
111  | literal [term.value = phoenix::arg1]
112  | func [term.value = phoenix::arg1]
113  | identifier [term.value = phoenix::bind(&MathExpressionGrammar::Lookup)(self, phoenix::arg1)]
114  ;
115 
116  func
117  =( boost::spirit::str_p("exp") >> term [func.value = F_exp(phoenix::arg1)]
118  | boost::spirit::str_p("log10") >> term [func.value = F_log10(phoenix::arg1)]
119  | boost::spirit::str_p("log") >> term [func.value = F_log(phoenix::arg1)]
120  | boost::spirit::str_p("sin") >> term [func.value = F_sin(phoenix::arg1)]
121  | boost::spirit::str_p("cos") >> term [func.value = F_cos(phoenix::arg1)]
122  | boost::spirit::str_p("tan") >> term [func.value = F_tan(phoenix::arg1)]
123  )
124  ;
125 
126  factor
127  = term [factor.value = phoenix::arg1]
128  >> *(
129  ('^' >> factor [factor.value = power2(factor.value, phoenix::arg1)])
130  // | (factor [factor.value *= phoenix::arg1]) // multiplication without * is a pain in the ass
131  )
132  ;
133 
134  multdiv
135  = factor [multdiv.value = phoenix::arg1]
136  >> *(
137  ('*' >> factor [multdiv.value *= phoenix::arg1])
138  | ('/' >> factor [multdiv.value /= phoenix::arg1])
139  )
140  ;
141 
142  expression
143  = multdiv [expression.value = phoenix::arg1]
144  >> *(
145  ('+' >> multdiv [expression.value += phoenix::arg1])
146  | ('-' >> multdiv [expression.value -= phoenix::arg1])
147  )
148  ;
149 
150  identifier
151  = boost::spirit::lexeme_d [(boost::spirit::alpha_p | '_')
152  >> *(boost::spirit::alnum_p | '_')][
153  identifier.name = phoenix::construct_<std::string>(phoenix::arg1, phoenix::arg2)
154  ]
155  ;
156 
157  statement
158  = expression [phoenix::bind(&MathExpressionGrammar::SaveResult)(self, phoenix::arg1)]
159  >> (boost::spirit::end_p | ';')
160  ;
161 
162  literal
163  = boost::spirit::longest_d[
164  boost::spirit::int_p [literal.value = phoenix::arg1]
165  | boost::spirit::real_p [literal.value = phoenix::arg1]
166  ]
167  ;
168 
169  /*
170  BOOST_SPIRIT_DEBUG_NODE(identifier);
171  BOOST_SPIRIT_DEBUG_NODE(statement);
172  BOOST_SPIRIT_DEBUG_NODE(literal);
173 
174  BOOST_SPIRIT_DEBUG_NODE(term);
175  BOOST_SPIRIT_DEBUG_NODE(factor);
176  BOOST_SPIRIT_DEBUG_NODE(prefix);
177  BOOST_SPIRIT_DEBUG_NODE(multdiv);
178  BOOST_SPIRIT_DEBUG_NODE(expression);
179  BOOST_SPIRIT_DEBUG_NODE(literal);
180  BOOST_SPIRIT_DEBUG_NODE(func);
181  */
182  }
183 
184  boost::spirit::rule<ScannerT> const& start() const { return statement; }
185 
186  boost::spirit::rule<ScannerT> statement;
187  boost::spirit::rule<ScannerT, SStringClosure::context_t> identifier;
188  boost::spirit::rule<ScannerT, SValueClosure::context_t> term, factor, prefix, multdiv, expression, literal, func;
189 
190  };
191 
192  protected:
193  void SaveResult(const double val) const { *fResult = val; }
194 
196  double
197  Lookup(const std::string& symbol)
198  const
199  {
200  const auto& symbols = *fSymbols; //Symbols::GetSymbolMap();
201  const auto it1 = symbols.find(symbol);
202  if (it1 != symbols.end())
203  return it1->second;
204 
205  //if (fVariables)
206  {
207  const auto it2 = fVariables.find(symbol);
208  if (it2 != fVariables.end())
209  return it2->second;
210  }
211  // issue exception
212  const std::string err =
213  "The symbol '" + symbol + "' " +
214  "is not defined during the evaluaion with the MathExpressionGrammer\n";
215  ERROR(err);
216  throw XMLParseException(err);
217  return 1;
218  }
219 
220  public:
221  SymbolTable& GetVariables() { return fVariables; }
222  const SymbolTable& GetVariables() const { return fVariables; }
223  int GetNVariables() const { return fVariables.size(); }
224 
225  bool HasVariable(const std::string& name) const { return fVariables.count(name); }
226  void SetVariable(const std::string& name, const double& v) { fVariables[name] = v; }
227  double GetVariable(const std::string& name) const { return fVariables.find(name)->second; }
228 
229  private:
232  mutable double* fResult = nullptr;
233  };
234 
235 }
236 
237 
238 #include <utl/AugerUnits.h>
239 
240 namespace utl {
242 }
243 
244 
245 #endif
const phoenix::function< PowerToImpl2 > power2
#define FIMP_std(name)
boost::spirit::rule< ScannerT > const & start() const
const phoenix::function< F_log_Impl > F_log
boost::spirit::rule< ScannerT, SValueClosure::context_t > expression
void SaveResult(const double val) const
const SymbolTable & GetVariables() const
const phoenix::function< F_exp_Impl > F_exp
boost::spirit::rule< ScannerT, SStringClosure::context_t > identifier
MathExpressionGrammar(double &result, const utl::SymbolTable &sym)
boost::spirit::rule< ScannerT, SValueClosure::context_t > literal
double pow(const double x, const unsigned int i)
boost::spirit::rule< ScannerT, SValueClosure::context_t > func
T1 operator()(T1 &t1, T2 &t2) const
Boost spirit definition template (Read Boost Spirit documentation)
const Data result[]
boost::spirit::rule< ScannerT, SValueClosure::context_t > factor
const phoenix::function< F_sin_Impl > F_sin
bool HasVariable(const std::string &name) const
std::map< std::string, double > SymbolTable
Definition: SymbolTable.h:10
a second level trigger
Definition: XbT2.h:8
boost::spirit::rule< ScannerT, SValueClosure::context_t > prefix
definition(const MathExpressionGrammar &self)
utl::ExpressionParser< MathExpressionGrammar, AugerUnits > FunctionParser
boost::spirit::rule< ScannerT > statement
MathExpressionGrammar(double &result, const utl::SymbolTable &sym, utl::SymbolTable &vars)
const phoenix::function< F_log10_Impl > F_log10
boost::spirit::rule< ScannerT, SValueClosure::context_t > term
const phoenix::function< F_tan_Impl > F_tan
double GetVariable(const std::string &name) const
const phoenix::function< F_cos_Impl > F_cos
void SetVariable(const std::string &name, const double &v)
void SetResult(double &v) const
boost::spirit::rule< ScannerT, SValueClosure::context_t > multdiv

, generated on Tue Sep 26 2023.