102 lines
2.3 KiB
C++
102 lines
2.3 KiB
C++
#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
|