SMTK  @SMTK_VERSION@
Simulation Modeling Tool Kit
InfixExpressionEvaluation.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_InfixExpressionEvaluation_h
11 #define smtk_common_InfixExpressionEvaluation_h
12 
15 #include "smtk/CoreExports.h" // For SMTKCORE_EXPORT macro
16 #include "smtk/SystemConfig.h"
17 
18 #include <cmath>
19 #include <functional>
20 #include <map>
21 #include <string>
22 #include <vector>
23 
24 // EvaluationOrder, InfixOperators, EvaluationStack, and EvaluationStacks are
25 // taken from taocpp/PEGTL/src/example/pegtl/calculator.cpp.
26 
27 namespace smtk
28 {
29 namespace common
30 {
31 
32 // A function to be called when a subsymbol is matched.
33 // Should return the value of the subsymbol or false in second if the
34 // subsymbol cannot be evaluated.
35 using SubsymbolVisitor = std::function<std::pair<double, bool>(const std::string& symbol)>;
36 
37 enum class EvaluationOrder : int
38 {
39 };
40 
42 {
43  EvaluationOrder p;
44  std::function<double(double, double)> f;
45 };
46 
47 // Unlike InfixOperator, InfixFunctions does not have EvaluationOrder. We assume all functions have the
48 // same precedence on a given level of associativity.
49 struct SMTKCORE_EXPORT InfixFunction
50 {
51  std::function<double(double)> f;
52 };
53 
54 class SMTKCORE_EXPORT EvaluationStack
55 {
56 public:
57  void push(const InfixOperator& b)
58  {
59  while (!m_operators.empty() && m_operators.back().p <= b.p)
60  {
61  reduce();
62  }
63  m_operators.push_back(b);
64  }
65 
66  void push(const double l) { m_operands.push_back(l); }
67 
68  double finish()
69  {
70  while (!m_operators.empty())
71  {
72  reduce();
73  }
74 
75  const double result = m_operands.back();
76  m_operands.clear();
77  return result;
78  }
79 
80 private:
81  std::vector<InfixOperator> m_operators;
82  std::vector<double> m_operands;
83 
84  void reduce()
85  {
86  const double r = m_operands.back();
87  m_operands.pop_back();
88  const double l = m_operands.back();
89  m_operands.pop_back();
90 
91  const InfixOperator o = m_operators.back();
92  m_operators.pop_back();
93 
94  m_operands.push_back(o.f(l, r));
95  }
96 };
97 
98 class SMTKCORE_EXPORT EvaluationStacks
99 {
100 public:
102  : m_functionForNextOpen([](double d) { return d; })
103  {
104  open();
105  }
106 
107  void open()
108  {
109  // The result of this StackLevel is itself unless |m_functionForNextOpen|
110  // is set before the next call to open().
111  m_stacks.emplace_back(StackLevel(EvaluationStack(), m_functionForNextOpen));
112  m_functionForNextOpen = [](double d) { return d; };
113  }
114 
115  void setFunctionForNextOpen(const std::function<double(double)>& functionForNextOpen)
116  {
117  m_functionForNextOpen = functionForNextOpen;
118  }
119 
120  template<typename T>
121  void push(const T& t)
122  {
123  m_stacks.back().first.push(t);
124  }
125 
126  void close()
127  {
128  // finish()es the stack and calls this StackLevel's function on the result.
129  const double result = m_stacks.back().second(m_stacks.back().first.finish());
130  m_stacks.pop_back();
131  m_stacks.back().first.push(result);
132  }
133 
134  double finish() { return m_stacks.back().first.finish(); }
135 
136 private:
137  using StackLevel = std::pair<EvaluationStack, std::function<double(double)>>;
138 
139  std::vector<StackLevel> m_stacks;
140  std::function<double(double)> m_functionForNextOpen;
141 };
142 
143 class SMTKCORE_EXPORT InfixOperators
144 {
145 public:
147  {
148  insert("*", EvaluationOrder(5), [](const double l, const double r) { return l * r; });
149  insert("/", EvaluationOrder(5), [](const double l, const double r) { return l / r; });
150  insert("+", EvaluationOrder(6), [](const double l, const double r) { return l + r; });
151  insert("-", EvaluationOrder(6), [](const double l, const double r) { return l - r; });
152  insert("^", EvaluationOrder(4), [](const double l, const double r) { return std::pow(l, r); });
153  }
154 
155  void insert(
156  const std::string& name,
157  const EvaluationOrder p,
158  const std::function<double(double, double)>& f)
159  {
160  m_ops.insert(std::make_pair(name, InfixOperator{ p, f }));
161  }
162 
163  const std::map<std::string, InfixOperator>& ops() const noexcept { return m_ops; }
164 
165 private:
166  std::map<std::string, InfixOperator> m_ops;
167 };
168 
169 class SMTKCORE_EXPORT InfixFunctions
170 {
171 public:
173  {
174  insert("sin", [](const double x) { return std::sin(x); });
175  insert("cos", [](const double x) { return std::cos(x); });
176  insert("tan", [](const double x) { return std::tan(x); });
177  insert("asin", [](const double x) { return std::asin(x); });
178  insert("acos", [](const double x) { return std::acos(x); });
179  insert("atan", [](const double x) { return std::atan(x); });
180  insert("sinh", [](const double x) { return std::sinh(x); });
181  insert("cosh", [](const double x) { return std::cosh(x); });
182  insert("tanh", [](const double x) { return std::tanh(x); });
183  insert("asinh", [](const double x) { return std::asinh(x); });
184  insert("acosh", [](const double x) { return std::acosh(x); });
185  insert("atanh", [](const double x) { return std::atanh(x); });
186  insert("ln", [](const double x) { return std::log(x); });
187  insert("log10", [](const double x) { return std::log10(x); });
188  insert("exp", [](const double x) { return std::exp(x); });
189  insert("sqrt", [](const double x) { return std::sqrt(x); });
190  }
191 
192  void insert(const std::string& name, const std::function<double(double)>& f)
193  {
194  m_functions.insert(std::make_pair(name, InfixFunction{ f }));
195  }
196 
197  const std::map<std::string, InfixFunction>& funcs() const noexcept { return m_functions; }
198 
199 private:
200  std::map<std::string, InfixFunction> m_functions;
201 };
202 
203 } // namespace common
204 } // namespace smtk
205 
206 #endif // smtk_common_InfixExpressionEvaluation_h
smtk
The main namespace for the Simulation Modeling Tool Kit (SMTK).
Definition: doc.h:33
smtk::common::InfixFunction
Definition: InfixExpressionEvaluation.h:49
smtk::common::InfixOperator
Definition: InfixExpressionEvaluation.h:41
smtk::common::InfixOperators
Definition: InfixExpressionEvaluation.h:143
smtk::common::InfixFunctions
Definition: InfixExpressionEvaluation.h:169
smtk::common::EvaluationStacks
Definition: InfixExpressionEvaluation.h:98
smtk::common::EvaluationStack
Definition: InfixExpressionEvaluation.h:54