Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cmath>
- #include <cstdlib>
- #include <limits>
- #include <iterator>
- #include <boost/math/constants/constants.hpp>
- #include <boost/spirit/include/phoenix.hpp>
- #include <boost/spirit/include/qi.hpp>
- namespace expression {
- namespace {
- struct lazy_pow_ {
- template <typename lhs_t, typename rhs_t>
- struct result {
- typedef lhs_t type;
- };
- template <typename lhs_t, typename rhs_t>
- lhs_t operator()(lhs_t x, rhs_t y) const {
- return std::pow(x, y);
- }
- };
- struct lazy_ufunc_ {
- template <typename func_t, typename t>
- struct result {
- typedef t type;
- };
- template <typename func_t, typename t>
- t operator()(func_t f, t a) const {
- return f(a);
- }
- };
- struct lazy_bfunc_ {
- template <typename func_t, typename t1, typename t2>
- struct result {
- typedef t1 type;
- };
- template <typename func_t, typename t1, typename t2>
- t1 operator()(func_t f, t1 a, t2 b) const {
- return f(a, b);
- }
- };
- } // namespace anonymous
- template <typename fpt, typename iterator_t>
- struct grammar : boost::spirit::qi::grammar<
- iterator_t, fpt(), boost::spirit::ascii::space_type>
- {
- // symbol table for constants like "pi"
- struct constant_ : boost::spirit::qi::symbols<
- typename std::iterator_traits<iterator_t>::value_type,
- fpt>
- {
- constant_() {
- this->add
- ("pi" ,boost::math::constants::pi<fpt>())
- ("e" ,boost::math::constants::e<fpt>())
- ;
- }
- } constant;
- // symbol table for unary functions like "abs"
- struct ufunc_ : boost::spirit::qi::symbols<
- typename std::iterator_traits<iterator_t>::value_type,
- fpt (*)(fpt)>
- {
- ufunc_() {
- this->add
- ("abs" ,(fpt (*)(fpt)) std::abs)
- ("acos" ,(fpt (*)(fpt)) std::acos)
- ("asin" ,(fpt (*)(fpt)) std::asin)
- ("atan" ,(fpt (*)(fpt)) std::atan)
- ("ceil" ,(fpt (*)(fpt)) std::ceil)
- ("cos" ,(fpt (*)(fpt)) std::cos)
- ("cosh" ,(fpt (*)(fpt)) std::cosh)
- ("exp" ,(fpt (*)(fpt)) std::exp)
- ("floor" ,(fpt (*)(fpt)) std::floor)
- ("ln" ,(fpt (*)(fpt)) std::log)
- ("log" ,(fpt (*)(fpt)) std::log10)
- ("sin" ,(fpt (*)(fpt)) std::sin)
- ("sinh" ,(fpt (*)(fpt)) std::sinh)
- ("sqrt" ,(fpt (*)(fpt)) std::sqrt)
- ("tan" ,(fpt (*)(fpt)) std::tan)
- ("tanh" ,(fpt (*)(fpt)) std::tanh)
- ;
- }
- } ufunc;
- // symbol table for binary functions like "pow"
- struct bfunc_ : boost::spirit::qi::symbols<
- typename std::iterator_traits<iterator_t>::value_type,
- fpt (*)(fpt, fpt)>
- {
- bfunc_() {
- this->add
- ("pow" ,(fpt (*)(fpt, fpt)) std::pow)
- ("atan2" ,(fpt (*)(fpt, fpt)) std::atan2)
- ("root" ,(fpt (*)(fpt, fpt)) [](double nb, double p){ return std::pow(nb, 1/p); })
- ;
- }
- } bfunc;
- boost::spirit::qi::rule<iterator_t, fpt(), boost::spirit::ascii::space_type>
- expression,
- term,
- factor,
- primary;
- grammar() : grammar::base_type(expression) {
- using namespace boost::phoenix;
- using namespace boost::spirit::qi;
- real_parser<fpt, real_policies<fpt>> real;
- function<lazy_pow_> lazy_pow;
- function<lazy_ufunc_> lazy_ufunc;
- function<lazy_bfunc_> lazy_bfunc;
- expression =
- term[_val = _1] >>
- *( ('+' >> term[_val += _1])
- | ('-' >> term[_val -= _1])
- )
- ;
- term =
- factor[_val = _1] >>
- *( ('*' >> factor[_val *= _1])
- | ('/' >> factor[_val /= _1])
- )
- ;
- factor =
- primary[_val = _1] >>
- *( ("**" >> factor[_val = lazy_pow(_val, _1)])
- )
- ;
- primary =
- real[_val = _1]
- | '(' >> expression[_val = _1] >> ')'
- | ('-' >> primary[_val = -_1])
- | ('+' >> primary[_val = _1])
- | no_case[constant][_val = _1]
- | (no_case[ufunc]
- >> '(' >> expression >> ')')[_val = lazy_ufunc(_1, _2)]
- | (no_case[bfunc]
- >> '(' >> expression >> ',' >> expression >> ')')[_val = lazy_bfunc(_1,_2,_3)]
- ;
- }
- };
- } // end namespace expression
- ///////////////////////////////////////////////////////////////////////////////
- // Main program
- ///////////////////////////////////////////////////////////////////////////////
- int main()
- {
- typedef std::string::const_iterator iterator_t;
- typedef expression::grammar<double, iterator_t> grammar_t;
- using namespace boost::spirit;
- std::string str;
- while (std::getline(std::cin, str)) {
- if (str.empty() || str[0] == 'q' || str[0] == 'Q')
- break;
- const grammar_t eg;
- double result;
- iterator_t iter = str.begin();
- iterator_t end = str.end();
- bool r = qi::phrase_parse(iter, end, eg, ascii::space, result);
- if (r && iter == end) {
- std::cout << " \033[33m" << str << "\033[32m = " << result << "\033[0m" << std::endl;
- return EXIT_SUCCESS;
- }
- else {
- std::string padd(std::distance(iter, end), ' ');
- std::cout << "\033[1;31merror:\033[0m " << str << '\n'
- << " " << padd << "\033[32m^\033[0m" << std::endl;
- return EXIT_FAILURE;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement