eis/mix_cc/matheval/matheval.cpp

102 lines
2.3 KiB
C++
Raw Permalink Normal View History

#define MATHEVAL_IMPLEMENTATION
#include "matheval.hpp"
#include "ast.hpp"
#include "evaluator.hpp"
#include "parser.hpp"
#include <memory>
#include <stdexcept>
#include <string>
namespace mix_cc {
namespace matheval {
class Parser::impl {
ast::operand ast;
public:
void parse(std::string const& expr) {
auto ast_ = ast::expression{};
auto first = expr.begin();
auto last = expr.end();
boost::spirit::x3::ascii::space_type space;
bool r = phrase_parse(first, last, grammar(), space, ast_);
if (!r || first != last) {
std::string rest(first, last);
throw std::runtime_error("Parsing failed at " + rest); // NOLINT
}
ast = ast_;
}
void optimize() { ast = boost::apply_visitor(ast::ConstantFolder{}, ast); }
double evaluate(std::map<std::string, double> const& st) {
return boost::apply_visitor(ast::eval{st}, ast);
}
};
Parser::Parser() : pimpl{std::make_unique<Parser::impl>()} {}
Parser::~Parser() {}
void Parser::parse(std::string const& expr) { pimpl->parse(expr); }
void Parser::optimize() { pimpl->optimize(); }
double Parser::evaluate(std::map<std::string, double> const& st) {
return pimpl->evaluate(st);
}
class Expression::impl {
ast::operand ast;
std::map<std::string, double>* st_ptr;
public:
void parse(std::string const& expr) {
auto ast_ = ast::expression{};
auto first = expr.begin();
auto last = expr.end();
boost::spirit::x3::ascii::space_type space;
bool r = phrase_parse(first, last, grammar(), space, ast_);
if (!r || first != last) {
std::string rest(first, last);
throw std::runtime_error("Parsing failed at " + rest); // NOLINT
}
ast = ast_;
}
void set_variable(std::map<std::string, double>* const ptr) {
this->st_ptr = ptr;
}
void optimize() { ast = boost::apply_visitor(ast::ConstantFolder{}, ast); }
double evaluate() { return boost::apply_visitor(ast::eval{*st_ptr}, ast); }
};
Expression::Expression(std::string const& math_expr,
std::map<std::string, double>* const ptr)
: pimpl{std::make_unique<Expression::impl>()} {
pimpl->parse(math_expr);
pimpl->optimize();
pimpl->set_variable(ptr);
}
Expression::~Expression() {}
double Expression::evaluate() { return pimpl->evaluate(); }
} // namespace matheval
} // namespace mix_cc