1#ifndef SXEVAL_SXEVAL_HPP
2#define SXEVAL_SXEVAL_HPP
28 std::function<T(void)>(
const std::string&)>;
61 template <
typename OP>
184 std::unique_ptr<IInstruction<T>> instruct;
186 std::vector<Node> subnodes;
193 static void _skipChars(
const std::string&
s,
size_t*
idx);
194 static std::string _getNextSymbol(
const std::string&
s,
size_t*
idx);
197 static void _fillParents(Node& parent);
198 static void _buildTreeStr(std::ostream&
oss,
const Node&
node,
size_t depth
200 T _interpret(
const std::string&
exp,
size_t*
idx,
208 operations::OperationsFactory<T> _operationsFactory;
209 std::vector<AOperation<T>*> _operations;
210 std::vector<EncapsulatedVariable<T>*> _encapsulated;
212 std::string _expression;
226 return os <<
obj.toString();
240 _encapsulated.clear();
241 _expression = expression;
243 _lastOperation = _build(&idx, resolveVariable, resolveEncapsulated);
244 _fillParents(_lastOperation);
249 if (_operations.size() == 0) {
250 throw std::runtime_error(
"No operations found");
252 for (
const auto& op : _encapsulated) {
255 for (
const auto& op : _operations) {
258 return _operations.back()->getResult();
267 return _interpret(expression, &idx, resolveVariable, resolveEncapsulated);
275 _skipChars(exp, idx);
277 if (exp[*idx] ==
'(') {
280 const auto symbol = _getNextSymbol(exp, idx);
281 std::vector<std::unique_ptr<IInstruction<T>>> args;
282 std::vector<IInstruction<T>*> pargs;
283 _skipChars(exp, idx);
284 while (exp[*idx] !=
')') {
285 const auto val = _interpret(exp, idx, resolveVariable,
286 resolveEncapsulated);
288 pargs.push_back(args.back().get());
289 _skipChars(exp, idx);
292 return _operationsFactory.compute(symbol, pargs);
296 const auto symbol = _getNextSymbol(exp, idx);
299 res = StringToType<T>(symbol);
303 res = resolveVariable(symbol);
308 const auto get = resolveEncapsulated(symbol);
313 if (symbol ==
"true") {
315 }
else if (symbol ==
"false") {
318 throw std::runtime_error(
"Unknown variable: " + symbol);
329 std::ostringstream oss;
330 _buildTreeStr(oss, _lastOperation, 0);
336 while (s[*i] ==
' ' || s[*i] ==
'\t' || s[*i] ==
'\n' || s[*i] ==
'\r' )
347 while (c !=
' ' && c !=
'\t' && c !=
'\n' && c !=
'\r' && c !=
'('
359 const resolveVariable_t<T>& resolveVariable,
360 const resolveEncapsulated_t<T>& resolveEncapsulated)
364 std::ostringstream oss;
365 oss <<
"[DEBUG] " << __FILE__ <<
":" << __LINE__
366 <<
" in " << __func__ <<
"(): " <<
"parsing '"
367 << _expression <<
"'\n";
368 std::cerr << oss.str();
371 _skipChars(_expression, idx);
373 if (_expression[*idx] ==
'(') {
376 const auto symbol = _getNextSymbol(_expression, idx);
378 node.parent =
nullptr;
381 node.id = nodeCount++;
382 std::ostringstream oss;
383 oss <<
"[DEBUG] " << __FILE__ <<
":" << __LINE__
384 <<
" in " << __func__ <<
"(): node " << node.id
385 <<
": found operation " << symbol <<
"\n";
386 std::cerr << oss.str();
389 _skipChars(_expression, idx);
390 while (_expression[*idx] !=
')') {
391 node.subnodes.push_back(_build(idx, resolveVariable,
392 resolveEncapsulated));
395 std::ostringstream oss;
396 oss <<
"[DEBUG] " << __FILE__ <<
":" << __LINE__
397 <<
" in " << __func__ <<
"(): -> node "
398 << node.subnodes.back().id <<
" added to node " << node.id
400 std::cerr << oss.str();
403 _skipChars(_expression, idx);
406 std::vector<IInstruction<T>*> args;
407 for (
auto& subnode : node.subnodes) {
408 args.push_back(subnode.instruct.get());
410 node.instruct = _operationsFactory.create(symbol, args);
411 _operations.push_back(
412 dynamic_cast<AOperation<T>*
>(node.instruct.get()));
413 return std::move(node);
417 const auto symbol = _getNextSymbol(_expression, idx);
420 T val = StringToType<T>(symbol);
421 node = { std::unique_ptr<IInstruction<T>>(
new Value<T>(val)),
425 node.id = nodeCount++;
426 std::ostringstream oss;
427 oss <<
"[DEBUG] " << __FILE__ <<
":" << __LINE__
428 <<
" in " << __func__ <<
"(): node " << node.id
429 <<
": found value " << symbol <<
" (="
430 << node.instruct->getResult() <<
")\n";
431 std::cerr << oss.str();
437 T& var = resolveVariable(symbol);
439 std::unique_ptr<IInstruction<T>>(
440 new Variable<T>(var, symbol)
444 node.id = nodeCount++;
445 std::ostringstream oss;
446 oss <<
"[DEBUG] " << __FILE__ <<
":" << __LINE__
447 <<
" in " << __func__ <<
"(): node " << node.id
448 <<
": found variable " << symbol <<
" (="
449 << node.instruct->getResult() <<
")\n";
450 std::cerr << oss.str();
457 auto get = resolveEncapsulated(symbol);
459 std::unique_ptr<IInstruction<T>>(
460 new EncapsulatedVariable<T>(get, symbol)
462 _encapsulated.push_back(
463 dynamic_cast<EncapsulatedVariable<T>*
>(
464 node.instruct.get()));
467 node.id = nodeCount++;
468 std::ostringstream oss;
469 oss <<
"[DEBUG] " << __FILE__ <<
":" << __LINE__
470 <<
" in " << __func__ <<
"(): node " << node.id
471 <<
": found encapsulated variable " << symbol
472 <<
" (=" << node.instruct->getResult() <<
")\n";
473 std::cerr << oss.str();
479 if (symbol ==
"true") {
481 std::unique_ptr<IInstruction<T>>(
new Value<T>(1)),
483 }
else if (symbol ==
"false") {
485 std::unique_ptr<IInstruction<T>>(
new Value<T>(0)),
488 throw std::runtime_error(
"Unknown variable: " + symbol);
492 node.id = nodeCount++;
493 std::ostringstream oss;
494 oss <<
"[DEBUG] " << __FILE__ <<
":" << __LINE__
495 <<
" in " << __func__ <<
"(): node " << node.id
496 <<
": found boolean value " << symbol
497 <<
" (=" << node.instruct->getResult() <<
")\n";
498 std::cerr << oss.str();
510 for (
auto& child : parent.subnodes) {
511 child.parent = &parent;
521 for (
size_t i = 0; i < depth - 1; ++i) {
522 const Node* parent = &node;
523 const Node* child =
nullptr;
524 for (
size_t j = 0; j < depth - i; ++j) {
526 parent = parent->parent;
528 if (!(parent !=
nullptr && parent->subnodes.back().instruct.get()
529 == child->instruct.get()))
536 if (node.parent !=
nullptr &&
537 node.parent->subnodes.back().instruct.get() != node.instruct.get())
544 oss << node.instruct->toString() << std::endl;
545 for (
const auto& child : node.subnodes) {
546 _buildTreeStr(oss, child, depth + 1);
The IInstruction class is an interface for any instructions.
Definition IInstruction.hpp:21
The SXEval class is used to evaluate s-expressions.
Definition SXEval.hpp:48
void registerOperation()
Register an operation.
Definition SXEval.hpp:62
T interpret(const std::string &expression, const resolveVariable_t< T > &resolveVariable=resolveVariable_t< T >(), const resolveEncapsulated_t< T > &resolveEncapsulated=resolveEncapsulated_t< T >()) const
Compute the result of an expression without building its tree.
Definition SXEval.hpp:262
T execute() const
Compute the result of the expression tree.
Definition SXEval.hpp:248
T interpret(const std::string &expression, const resolveEncapsulated_t< T > &resolveEncapsulated=resolveEncapsulated_t< T >(), const resolveVariable_t< T > &resolveVariable=resolveVariable_t< T >()) const
Compute the result of an expression without building its tree.
Definition SXEval.hpp:168
std::string toString() const
Convert the expression tree to a string representation.
Definition SXEval.hpp:328
SXEval()
Default constructor.
Definition SXEval.hpp:53
void build(const std::string &expression, const resolveEncapsulated_t< T > &resolveEncapsulated=resolveEncapsulated_t< T >(), const resolveVariable_t< T > &resolveVariable=resolveVariable_t< T >())
Build the expression tree from a s-expression.
Definition SXEval.hpp:104
void build(const std::string &expression, const resolveVariable_t< T > &resolveVariable=resolveVariable_t< T >(), const resolveEncapsulated_t< T > &resolveEncapsulated=resolveEncapsulated_t< T >())
Build the expression tree from a s-expression.
Definition SXEval.hpp:235
The Value class represents a constant value in the SXEval library.
Definition Value.hpp:20
Definition AOperation.hpp:8
std::function< T &(const std::string &)> resolveVariable_t
Definition SXEval.hpp:25
std::ostream & operator<<(std::ostream &os, const IInstruction< T > &obj)
Output stream operator for AInstruction.
Definition IInstruction.hpp:51
std::function< std::function< T(void)>(const std::string &)> resolveEncapsulated_t
Definition SXEval.hpp:28
std::enable_if< std::is_unsigned< T >::value, T >::type Absolute(const T &a)
Perform an absolute value operation on types T.
Definition utils.hpp:262