300 lines
9.4 KiB
C++
300 lines
9.4 KiB
C++
|
|
#ifndef MATHEVAL_IMPLEMENTATION
|
||
|
|
#error "Do not include parser_def.hpp directly!"
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#pragma once
|
||
|
|
|
||
|
|
#include "ast.hpp"
|
||
|
|
#include "ast_adapted.hpp"
|
||
|
|
#include "math.hpp"
|
||
|
|
#include "parser.hpp"
|
||
|
|
#include<mix_cc/math/gitbit.h>
|
||
|
|
#include<mix_cc/math/log.h>
|
||
|
|
#include <boost/math/constants/constants.hpp>
|
||
|
|
#include <boost/spirit/home/x3.hpp>
|
||
|
|
|
||
|
|
#include <cmath>
|
||
|
|
#include <iostream>
|
||
|
|
#include <limits>
|
||
|
|
#include <string>
|
||
|
|
|
||
|
|
namespace mix_cc {
|
||
|
|
|
||
|
|
namespace matheval {
|
||
|
|
|
||
|
|
namespace x3 = boost::spirit::x3;
|
||
|
|
|
||
|
|
namespace parser {
|
||
|
|
|
||
|
|
// LOOKUP
|
||
|
|
|
||
|
|
struct constant_ : x3::symbols<double> {
|
||
|
|
constant_() {
|
||
|
|
// clang-format off
|
||
|
|
add
|
||
|
|
("e" , boost::math::constants::e<double>())
|
||
|
|
("epsilon", std::numeric_limits<double>::epsilon())
|
||
|
|
("phi" , boost::math::constants::phi<double>())
|
||
|
|
("pi" , boost::math::constants::pi<double>())
|
||
|
|
("true" , 1)
|
||
|
|
("false" , 0)
|
||
|
|
;
|
||
|
|
// clang-format on
|
||
|
|
}
|
||
|
|
} constant;
|
||
|
|
|
||
|
|
struct ufunc_ : x3::symbols<double (*)(double)> {
|
||
|
|
ufunc_() {
|
||
|
|
// clang-format off
|
||
|
|
add
|
||
|
|
("abs" , static_cast<double (*)(double)>(&std::abs))
|
||
|
|
// ("acos" , static_cast<double (*)(double)>(&std::acos))
|
||
|
|
// ("acosh" , static_cast<double (*)(double)>(&std::acosh))
|
||
|
|
// ("asin" , static_cast<double (*)(double)>(&std::asin))
|
||
|
|
// ("asinh" , static_cast<double (*)(double)>(&std::asinh))
|
||
|
|
// ("atan" , static_cast<double (*)(double)>(&std::atan))
|
||
|
|
// ("atanh" , static_cast<double (*)(double)>(&std::atanh))
|
||
|
|
// ("cbrt" , static_cast<double (*)(double)>(&std::cbrt))
|
||
|
|
("ceil" , static_cast<double (*)(double)>(&std::ceil))
|
||
|
|
("cos" , static_cast<double (*)(double)>(&std::cos))
|
||
|
|
// ("cosh" , static_cast<double (*)(double)>(&std::cosh))
|
||
|
|
// ("deg" , static_cast<double (*)(double)>(&math::deg))
|
||
|
|
// ("erf" , static_cast<double (*)(double)>(&std::erf))
|
||
|
|
// ("erfc" , static_cast<double (*)(double)>(&std::erfc))
|
||
|
|
("exp" , static_cast<double (*)(double)>(&std::exp))
|
||
|
|
// ("exp2" , static_cast<double (*)(double)>(&std::exp2))
|
||
|
|
("floor" , static_cast<double (*)(double)>(&std::floor))
|
||
|
|
("isinf" , static_cast<double (*)(double)>(&math::isinf))
|
||
|
|
("isnan" , static_cast<double (*)(double)>(&math::isnan))
|
||
|
|
("log" , static_cast<double (*)(double)>(&std::log))
|
||
|
|
("ln" , static_cast<double (*)(double)>(&std::log))
|
||
|
|
("log2" , static_cast<double (*)(double)>(&std::log2))
|
||
|
|
("log10" , static_cast<double (*)(double)>(&std::log10))
|
||
|
|
// ("rad" , static_cast<double (*)(double)>(&math::rad))
|
||
|
|
("round" , static_cast<double (*)(double)>(&std::round))
|
||
|
|
// ("sgn" , static_cast<double (*)(double)>(&math::sgn))
|
||
|
|
("sin" , static_cast<double (*)(double)>(&std::sin))
|
||
|
|
// ("sinh" , static_cast<double (*)(double)>(&std::sinh))
|
||
|
|
("sqrt" , static_cast<double (*)(double)>(&std::sqrt))
|
||
|
|
("tan" , static_cast<double (*)(double)>(&std::tan))
|
||
|
|
// ("tanh" , static_cast<double (*)(double)>(&std::tanh))
|
||
|
|
// ("tgamma", static_cast<double (*)(double)>(&std::tgamma))
|
||
|
|
("B2N", static_cast<double (*)(double)>(&mix_cc::B2N))
|
||
|
|
;
|
||
|
|
// clang-format on
|
||
|
|
}
|
||
|
|
} ufunc;
|
||
|
|
|
||
|
|
struct bfunc_ : x3::symbols<double (*)(double, double)> {
|
||
|
|
bfunc_() {
|
||
|
|
// clang-format off
|
||
|
|
add
|
||
|
|
// ("atan2", static_cast<double (*)(double, double)>(&std::atan2))
|
||
|
|
("max" , static_cast<double (*)(double, double)>(&std::fmax))
|
||
|
|
("min" , static_cast<double (*)(double, double)>(&std::fmin))
|
||
|
|
("pow" , static_cast<double (*)(double, double)>(&std::pow))
|
||
|
|
("gitbit", static_cast<double (*)(double, double)>(&mix_cc::gitbit))
|
||
|
|
("log", static_cast<double (*)(double, double)>(&mix_cc::log))
|
||
|
|
("XOR", static_cast<double (*)(double, double)>(&mix_cc::XOR))
|
||
|
|
;
|
||
|
|
// clang-format on
|
||
|
|
}
|
||
|
|
} bfunc;
|
||
|
|
|
||
|
|
struct unary_op_ : x3::symbols<double (*)(double)> {
|
||
|
|
unary_op_() {
|
||
|
|
// clang-format off
|
||
|
|
add
|
||
|
|
("+", static_cast<double (*)(double)>(&math::plus))
|
||
|
|
("-", static_cast<double (*)(double)>(&math::minus))
|
||
|
|
("!", static_cast<double (*)(double)>(&math::unary_not))
|
||
|
|
;
|
||
|
|
// clang-format on
|
||
|
|
}
|
||
|
|
} unary_op;
|
||
|
|
|
||
|
|
struct additive_op_ : x3::symbols<double (*)(double, double)> {
|
||
|
|
additive_op_() {
|
||
|
|
// clang-format off
|
||
|
|
add
|
||
|
|
("+", static_cast<double (*)(double, double)>(&math::plus))
|
||
|
|
("-", static_cast<double (*)(double, double)>(&math::minus))
|
||
|
|
;
|
||
|
|
// clang-format on
|
||
|
|
}
|
||
|
|
} additive_op;
|
||
|
|
|
||
|
|
struct multiplicative_op_ : x3::symbols<double (*)(double, double)> {
|
||
|
|
multiplicative_op_() {
|
||
|
|
// clang-format off
|
||
|
|
add
|
||
|
|
("*", static_cast<double (*)(double, double)>(&math::multiplies))
|
||
|
|
("/", static_cast<double (*)(double, double)>(&math::divides))
|
||
|
|
("%", static_cast<double (*)(double, double)>(&std::fmod))
|
||
|
|
;
|
||
|
|
// clang-format on
|
||
|
|
}
|
||
|
|
} multiplicative_op;
|
||
|
|
|
||
|
|
struct logical_op_ : x3::symbols<double (*)(double, double)> {
|
||
|
|
logical_op_() {
|
||
|
|
// clang-format off
|
||
|
|
add
|
||
|
|
("&&", static_cast<double (*)(double, double)>(&math::logical_and))
|
||
|
|
("||", static_cast<double (*)(double, double)>(&math::logical_or))
|
||
|
|
;
|
||
|
|
// clang-format on
|
||
|
|
}
|
||
|
|
} logical_op;
|
||
|
|
|
||
|
|
struct relational_op_ : x3::symbols<double (*)(double, double)> {
|
||
|
|
relational_op_() {
|
||
|
|
// clang-format off
|
||
|
|
add
|
||
|
|
("<" , static_cast<double (*)(double, double)>(&math::less))
|
||
|
|
("<=", static_cast<double (*)(double, double)>(&math::less_equals))
|
||
|
|
(">" , static_cast<double (*)(double, double)>(&math::greater))
|
||
|
|
(">=", static_cast<double (*)(double, double)>(&math::greater_equals))
|
||
|
|
|
||
|
|
;
|
||
|
|
|
||
|
|
// clang-format on
|
||
|
|
}
|
||
|
|
} relational_op;
|
||
|
|
|
||
|
|
struct equality_op_ : x3::symbols<double (*)(double, double)> {
|
||
|
|
equality_op_() {
|
||
|
|
// clang-format off
|
||
|
|
add
|
||
|
|
("==", static_cast<double (*)(double, double)>(&math::equals))
|
||
|
|
("!=", static_cast<double (*)(double, double)>(&math::not_equals))
|
||
|
|
;
|
||
|
|
// clang-format on
|
||
|
|
}
|
||
|
|
} equality_op;
|
||
|
|
|
||
|
|
struct power_ : x3::symbols<double (*)(double, double)> {
|
||
|
|
power_() {
|
||
|
|
// clang-format off
|
||
|
|
add
|
||
|
|
("**", static_cast<double (*)(double, double)>(&std::pow))
|
||
|
|
;
|
||
|
|
// clang-format on
|
||
|
|
}
|
||
|
|
} power;
|
||
|
|
|
||
|
|
// ADL markers
|
||
|
|
|
||
|
|
struct expression_class;
|
||
|
|
struct logical_class;
|
||
|
|
struct equality_class;
|
||
|
|
struct relational_class;
|
||
|
|
struct additive_class;
|
||
|
|
struct multiplicative_class;
|
||
|
|
struct factor_class;
|
||
|
|
struct primary_class;
|
||
|
|
struct unary_class;
|
||
|
|
struct binary_class;
|
||
|
|
struct variable_class;
|
||
|
|
|
||
|
|
// clang-format off
|
||
|
|
|
||
|
|
// Rule declarations
|
||
|
|
|
||
|
|
auto const expression = x3::rule<expression_class , ast::expression>{"expression"};
|
||
|
|
auto const logical = x3::rule<logical_class , ast::expression>{"logical"};
|
||
|
|
auto const equality = x3::rule<equality_class , ast::expression>{"equality"};
|
||
|
|
auto const relational = x3::rule<relational_class , ast::expression>{"relational"};
|
||
|
|
auto const additive = x3::rule<additive_class , ast::expression>{"additive"};
|
||
|
|
auto const multiplicative = x3::rule<multiplicative_class, ast::expression>{"multiplicative"};
|
||
|
|
auto const factor = x3::rule<factor_class , ast::expression>{"factor"};
|
||
|
|
auto const primary = x3::rule<primary_class , ast::operand >{"primary"};
|
||
|
|
auto const unary = x3::rule<unary_class , ast::unary_op >{"unary"};
|
||
|
|
auto const binary = x3::rule<binary_class , ast::binary_op >{"binary"};
|
||
|
|
auto const variable = x3::rule<variable_class , std::string >{"variable"};
|
||
|
|
|
||
|
|
// Rule defintions
|
||
|
|
|
||
|
|
auto const expression_def =
|
||
|
|
logical
|
||
|
|
;
|
||
|
|
|
||
|
|
auto const logical_def =
|
||
|
|
equality >> *(logical_op > equality)
|
||
|
|
;
|
||
|
|
|
||
|
|
auto const equality_def =
|
||
|
|
relational >> *(equality_op > relational)
|
||
|
|
;
|
||
|
|
|
||
|
|
auto const relational_def =
|
||
|
|
additive >> *(relational_op > additive)
|
||
|
|
;
|
||
|
|
|
||
|
|
auto const additive_def =
|
||
|
|
multiplicative >> *(additive_op > multiplicative)
|
||
|
|
;
|
||
|
|
|
||
|
|
auto const multiplicative_def =
|
||
|
|
factor >> *(multiplicative_op > factor)
|
||
|
|
;
|
||
|
|
|
||
|
|
auto const factor_def =
|
||
|
|
primary >> *( power > factor )
|
||
|
|
;
|
||
|
|
|
||
|
|
auto const unary_def =
|
||
|
|
ufunc > '(' > expression > ')'
|
||
|
|
;
|
||
|
|
|
||
|
|
auto const binary_def =
|
||
|
|
bfunc > '(' > expression > ',' > expression > ')'
|
||
|
|
;
|
||
|
|
|
||
|
|
auto const variable_def =
|
||
|
|
x3::raw[x3::lexeme[x3::alpha >> *(x3::alnum | '_')]]
|
||
|
|
;
|
||
|
|
|
||
|
|
auto const primary_def =
|
||
|
|
x3::double_
|
||
|
|
| ('(' > expression > ')')
|
||
|
|
| (unary_op > primary)
|
||
|
|
| binary
|
||
|
|
| unary
|
||
|
|
| constant
|
||
|
|
| variable
|
||
|
|
;
|
||
|
|
|
||
|
|
BOOST_SPIRIT_DEFINE(
|
||
|
|
expression,
|
||
|
|
logical,
|
||
|
|
equality,
|
||
|
|
relational,
|
||
|
|
additive,
|
||
|
|
multiplicative,
|
||
|
|
factor,
|
||
|
|
primary,
|
||
|
|
unary,
|
||
|
|
binary,
|
||
|
|
variable
|
||
|
|
)
|
||
|
|
|
||
|
|
// clang-format on
|
||
|
|
|
||
|
|
struct expression_class {
|
||
|
|
template <typename Iterator, typename Exception, typename Context>
|
||
|
|
x3::error_handler_result on_error(Iterator&, Iterator const& last,
|
||
|
|
Exception const& x, Context const&) {
|
||
|
|
std::cout << "Expected " << x.which() << " at \""
|
||
|
|
<< std::string{x.where(), last} << "\"" << std::endl;
|
||
|
|
return x3::error_handler_result::fail;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
} // namespace parser
|
||
|
|
|
||
|
|
parser::expression_type grammar() { return parser::expression; }
|
||
|
|
|
||
|
|
} // namespace matheval
|
||
|
|
} // namespace mix_cc
|