SMTK  @SMTK_VERSION@
Simulation Modeling Tool Kit
InfixExpressionGrammarImpl.h
Go to the documentation of this file.
1 //=========================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //=========================================================================
10 #ifndef smtk_common_ExpressionGrammarImpl_h
11 #define smtk_common_ExpressionGrammarImpl_h
12 
14 #include <functional>
15 #include <iostream>
16 #include <map>
17 #include <sstream>
18 
19 #include "smtk/CoreExports.h"
20 
23 
24 #include <tao/pegtl.hpp>
25 #include <tao/pegtl/contrib/abnf.hpp>
26 #include <tao/pegtl/contrib/parse_tree.hpp>
27 
28 #ifdef ERROR_INVALID_FUNCTION
29 #undef ERROR_INVALID_FUNCTION
30 #endif
31 
32 namespace smtk
33 {
34 namespace common
35 {
36 
37 namespace expression_internal
38 {
39 
40 using namespace tao::pegtl;
41 
42 // clang-format off
43 
44 struct ignored
45  : space
46 {};
47 
49  : one< '+', '-', '*', '/', '^' >
50 {};
51 
52 struct symbol
53  : seq< abnf::ALPHA, star< sor< ranges< 'a', 'z', 'A', 'Z', '0', '9'>, one< '-', '_' > > > >
54 {};
55 
57  : seq< abnf::ALPHA, star < sor< ranges< 'a', 'z', 'A', 'Z', '0', '9' >, one< '-', '_' > > > >
58 {};
59 
60 // Rules for floating-point numbers are taken from
61 // taocpp/json/include/tao/json/internal/grammar.hpp.
62 struct digits
63  : plus< digit >
64 {};
65 
66 struct sign
67  : opt< one < '+', '-' > >
68 {};
69 
70 struct exp
71  : seq< one < 'e', 'E'>, opt< sign >, must< digits > >
72 {};
73 
74 struct frac
75  : if_must< one< '.' >, opt< digits > >
76 {};
77 
78 struct number
79  : seq< sign, digits, opt< frac >, opt< exp > >
80 {};
81 
82 struct expression;
83 
85  : if_must< function_name, star< ignored >, one< '(' >, star< ignored >, expression, star< ignored >, one< ')' > >
86 {};
87 
88 struct paren
89  : if_must< one< '(' >, expression, one< ')' > >
90 {};
91 
93  : if_must< one< '{' >, symbol, one< '}' > >
94 {};
95 
96 struct atomic
97  : sor< number, paren, infix_function, subsymbol_reference >
98 {};
99 
101  : list< atomic, infix_operator, ignored >
102 {};
103 
105  must< star< ignored >, expression, star< ignored >, eof >
106 {};
107 
108 // clang-format on
109 
110 // Our action base class inherits from |nothing| because every action must have
111 // apply() or apply0(). |nothing| tells PEGTL we're OK with this action doing
112 // nothing.
113 template<typename Rule>
114 struct ExpressionAction : nothing<Rule>
115 {
116 };
117 
118 template<>
120 {
121  template<typename ActionInput>
122  static void apply(
123  const ActionInput& in,
124  const InfixOperators& /* unused */,
125  EvaluationStacks& s,
126  const InfixFunctions& /* unused */,
127  const SubsymbolVisitor& /* unused */,
128  InfixExpressionError& /* unused: if we matched a number, this cannot be an invalid token */)
129  {
130  std::stringstream ss(in.string());
131  double v;
132  ss >> v;
133  s.push(v);
134  }
135 };
136 
137 template<>
139 {
140  template<typename ActionInput>
141  static void apply(
142  const ActionInput& in,
143  const InfixOperators& b,
144  EvaluationStacks& s,
145  const InfixFunctions& /* unused */,
146  const SubsymbolVisitor& /* unused */,
147  InfixExpressionError& err)
148  {
149  std::string str = in.string();
150  const std::map<std::string, InfixOperator>::const_iterator it = b.ops().find(str);
151  if (it != b.ops().end())
152  {
153  s.push(it->second);
154  }
155  else
156  {
157  // this is an invalid operator, but this rule would never be matched in
158  // that case.
159  err = InfixExpressionError::ERROR_UNKNOWN_OPERATOR;
160  throw parse_error("Invalid operator.", in);
161  }
162  }
163 };
164 
165 template<>
167 {
168  template<typename ActionInput>
169  static void apply(
170  const ActionInput& in,
171  const InfixOperators& /* unused */,
172  EvaluationStacks& s,
173  const InfixFunctions& funcs,
174  const SubsymbolVisitor& /* unused */,
175  InfixExpressionError& err)
176  {
177  std::string str = in.string();
178  std::size_t openingParenIdx = str.find_first_of('(');
179  std::string functionName = str.substr(0, openingParenIdx);
180 
181  const std::map<std::string, InfixFunction>::const_iterator it =
182  funcs.funcs().find(functionName);
183  if (it != funcs.funcs().end())
184  {
185  s.setFunctionForNextOpen(it->second.f);
186  }
187  else
188  {
189  err = InfixExpressionError::ERROR_UNKNOWN_FUNCTION;
190  throw parse_error("Invalid function.", in);
191  }
192  }
193 };
194 
195 template<>
197 {
198  template<typename ActionInput>
199  static void apply(
200  const ActionInput& in,
201  const InfixOperators& /* unused */,
202  EvaluationStacks& s,
203  const InfixFunctions& /* unused */,
204  const SubsymbolVisitor& subFunc,
205  InfixExpressionError& err)
206  {
207  std::string str = in.string();
208 
209  // A substring that excludes the braces. I.e, "abc" is passed to subFunc
210  // when we matched "{abc}".
211  std::pair<double, bool> result = subFunc(str.substr(1, str.size() - 2));
212 
213  // TODO: if a subexpression evaluates to nan or inf, isn't that really a
214  // math error?
215  if (!result.second || std::isnan(result.first) || std::isinf(result.first))
216  {
217  err = InfixExpressionError::ERROR_SUBEVALUATION_FAILED;
218  throw parse_error("Subexpression could not be evaluated.", in);
219  }
220  else
221  {
222  s.push(result.first);
223  }
224  }
225 };
226 
227 template<>
228 struct ExpressionAction<one<'('>>
229 {
230  static void apply0(
231  const InfixOperators& /* unused */,
232  EvaluationStacks& s,
233  const InfixFunctions& /* unused */,
234  const SubsymbolVisitor& /* unused */,
235  InfixExpressionError& /* unused */)
236  {
237  s.open();
238  }
239 };
240 
241 template<>
242 struct ExpressionAction<one<')'>>
243 {
244  static void apply0(
245  const InfixOperators& /* unused */,
246  EvaluationStacks& s,
247  const InfixFunctions& /* unused */,
248  const SubsymbolVisitor& /* unused */,
249  InfixExpressionError& /* unused */)
250  {
251  s.close();
252  }
253 };
254 
255 } // namespace expression_internal
256 
257 } // namespace common
258 } // namespace smtk
259 
260 #endif // smtk_common_ExpressionGrammarImpl_h
smtk
The main namespace for the Simulation Modeling Tool Kit (SMTK).
Definition: doc.h:33
smtk::common::expression_internal::digits
Definition: InfixExpressionGrammarImpl.h:62
smtk::apply
std::enable_if< I==sizeof...(Ts), void >::type apply(Functor &f, std::tuple< Ts... > tup)
Apply a functor to each element of a tuple.
Definition: TupleTraits.h:455
smtk::common::expression_internal::frac
Definition: InfixExpressionGrammarImpl.h:74
smtk::common::expression_internal::atomic
Definition: InfixExpressionGrammarImpl.h:96
smtk::common::expression_internal::paren
Definition: InfixExpressionGrammarImpl.h:88
smtk::common::expression_internal::expression
Definition: InfixExpressionGrammarImpl.h:100
smtk::common::expression_internal::function_name
Definition: InfixExpressionGrammarImpl.h:56
smtk::common::expression_internal::exp
Definition: InfixExpressionGrammarImpl.h:70
smtk::common::expression_internal::infix_operator
Definition: InfixExpressionGrammarImpl.h:48
smtk::common::expression_internal::symbol
Definition: InfixExpressionGrammarImpl.h:52
smtk::common::InfixOperators
Definition: InfixExpressionEvaluation.h:143
smtk::common::expression_internal::subsymbol_reference
Definition: InfixExpressionGrammarImpl.h:92
smtk::common::expression_internal::infix_function
Definition: InfixExpressionGrammarImpl.h:84
InfixExpressionEvaluation.h
smtk::common::expression_internal::sign
Definition: InfixExpressionGrammarImpl.h:66
InfixExpressionError.h
smtk::common::expression_internal::ignored
Definition: InfixExpressionGrammarImpl.h:44
smtk::common::InfixFunctions
Definition: InfixExpressionEvaluation.h:169
smtk::common::expression_internal::number
Definition: InfixExpressionGrammarImpl.h:78
smtk::common::expression_internal::ExpressionAction
Definition: InfixExpressionGrammarImpl.h:114
smtk::common::expression_internal::expression_grammar
Definition: InfixExpressionGrammarImpl.h:104
smtk::common::EvaluationStacks
Definition: InfixExpressionEvaluation.h:98