Advertisement
unomadh

Using Boost Spirit 2.1+ to evaluate constant arithmetic expr

Feb 22nd, 2013
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.42 KB | None | 0 0
  1. #include <cmath>
  2. #include <cstdlib>
  3. #include <limits>
  4. #include <iterator>
  5.  
  6. #include <boost/math/constants/constants.hpp>
  7. #include <boost/spirit/include/phoenix.hpp>
  8. #include <boost/spirit/include/qi.hpp>
  9.  
  10. namespace expression {
  11. namespace {
  12.    
  13.     struct lazy_pow_ {
  14.         template <typename lhs_t, typename rhs_t>
  15.         struct result {
  16.             typedef lhs_t type;
  17.         };
  18.         template <typename lhs_t, typename rhs_t>
  19.         lhs_t operator()(lhs_t x, rhs_t y) const {
  20.             return std::pow(x, y);
  21.         }
  22.     };
  23.      
  24.     struct lazy_ufunc_ {
  25.         template <typename func_t, typename t>
  26.         struct result {
  27.             typedef t type;
  28.         };
  29.         template <typename func_t, typename t>
  30.         t operator()(func_t f, t a) const {
  31.             return f(a);
  32.         }
  33.     };
  34.      
  35.     struct lazy_bfunc_ {
  36.         template <typename func_t, typename t1, typename t2>
  37.         struct result {
  38.             typedef t1 type;
  39.         };
  40.         template <typename func_t, typename t1, typename t2>
  41.         t1 operator()(func_t f, t1 a, t2 b) const {
  42.             return f(a, b);
  43.         }
  44.     };
  45.  
  46. } // namespace anonymous
  47.  
  48.     template <typename fpt, typename iterator_t>
  49.     struct grammar : boost::spirit::qi::grammar<
  50.         iterator_t, fpt(), boost::spirit::ascii::space_type>
  51.     {
  52.         // symbol table for constants like "pi"
  53.         struct constant_ : boost::spirit::qi::symbols<
  54.             typename std::iterator_traits<iterator_t>::value_type,
  55.             fpt>
  56.         {
  57.             constant_() {
  58.                 this->add
  59.                 ("pi"       ,boost::math::constants::pi<fpt>())
  60.                 ("e"        ,boost::math::constants::e<fpt>())
  61.                 ;
  62.             }
  63.         } constant;
  64.          
  65.         // symbol table for unary functions like "abs"
  66.         struct ufunc_ : boost::spirit::qi::symbols<
  67.             typename std::iterator_traits<iterator_t>::value_type,
  68.             fpt (*)(fpt)>
  69.         {
  70.             ufunc_() {
  71.                 this->add
  72.                 ("abs"      ,(fpt (*)(fpt)) std::abs)
  73.                 ("acos"     ,(fpt (*)(fpt)) std::acos)
  74.                 ("asin"     ,(fpt (*)(fpt)) std::asin)
  75.                 ("atan"     ,(fpt (*)(fpt)) std::atan)
  76.                 ("ceil"     ,(fpt (*)(fpt)) std::ceil)
  77.                 ("cos"      ,(fpt (*)(fpt)) std::cos)
  78.                 ("cosh"     ,(fpt (*)(fpt)) std::cosh)
  79.                 ("exp"      ,(fpt (*)(fpt)) std::exp)
  80.                 ("floor"    ,(fpt (*)(fpt)) std::floor)
  81.                 ("ln"       ,(fpt (*)(fpt)) std::log)
  82.                 ("log"      ,(fpt (*)(fpt)) std::log10)
  83.                 ("sin"      ,(fpt (*)(fpt)) std::sin)
  84.                 ("sinh"     ,(fpt (*)(fpt)) std::sinh)
  85.                 ("sqrt"     ,(fpt (*)(fpt)) std::sqrt)
  86.                 ("tan"      ,(fpt (*)(fpt)) std::tan)
  87.                 ("tanh"     ,(fpt (*)(fpt)) std::tanh)
  88.                 ;
  89.             }
  90.         } ufunc;
  91.          
  92.         // symbol table for binary functions like "pow"
  93.         struct bfunc_ : boost::spirit::qi::symbols<
  94.             typename std::iterator_traits<iterator_t>::value_type,
  95.             fpt (*)(fpt, fpt)>
  96.         {
  97.             bfunc_() {
  98.                 this->add
  99.                 ("pow"      ,(fpt (*)(fpt, fpt)) std::pow)
  100.                 ("atan2"    ,(fpt (*)(fpt, fpt)) std::atan2)
  101.                 ("root"     ,(fpt (*)(fpt, fpt)) [](double nb, double p){ return std::pow(nb, 1/p); })
  102.                 ;
  103.             }
  104.         } bfunc;
  105.          
  106.         boost::spirit::qi::rule<iterator_t, fpt(), boost::spirit::ascii::space_type>
  107.             expression,
  108.             term,
  109.             factor,
  110.             primary;
  111.        
  112.         grammar() : grammar::base_type(expression) {
  113.             using namespace boost::phoenix;
  114.             using namespace boost::spirit::qi;
  115.            
  116.             real_parser<fpt, real_policies<fpt>> real;
  117.             function<lazy_pow_>     lazy_pow;
  118.             function<lazy_ufunc_>   lazy_ufunc;
  119.             function<lazy_bfunc_>   lazy_bfunc;
  120.              
  121.             expression =
  122.                 term[_val = _1] >>
  123.                 *(  ('+' >> term[_val += _1])
  124.                   | ('-' >> term[_val -= _1])
  125.                 )
  126.                 ;
  127.              
  128.             term =
  129.                 factor[_val = _1] >>
  130.                 *(  ('*' >> factor[_val *= _1])
  131.                   | ('/' >> factor[_val /= _1])
  132.                 )
  133.                 ;
  134.              
  135.             factor =
  136.                 primary[_val = _1] >>
  137.                 *(  ("**" >> factor[_val = lazy_pow(_val, _1)])
  138.                 )
  139.                 ;
  140.              
  141.             primary =
  142.                 real[_val = _1]
  143.                   | '(' >> expression[_val = _1] >> ')'
  144.                   | ('-' >> primary[_val = -_1])
  145.                   | ('+' >> primary[_val = _1])
  146.                   | no_case[constant][_val = _1]
  147.                   | (no_case[ufunc]
  148.                   >> '(' >> expression >> ')')[_val = lazy_ufunc(_1, _2)]
  149.                   | (no_case[bfunc]
  150.                   >> '(' >> expression >> ',' >> expression >> ')')[_val = lazy_bfunc(_1,_2,_3)]
  151.                 ;
  152.         }
  153.     };
  154. } // end namespace expression
  155.  
  156.  
  157. ///////////////////////////////////////////////////////////////////////////////
  158. //  Main program
  159. ///////////////////////////////////////////////////////////////////////////////
  160. int main()
  161. {
  162.     typedef std::string::const_iterator iterator_t;
  163.     typedef expression::grammar<double, iterator_t> grammar_t;
  164.     using namespace boost::spirit;
  165.    
  166.     std::string str;
  167.  
  168.     while (std::getline(std::cin, str)) {
  169.         if (str.empty() || str[0] == 'q' || str[0] == 'Q')
  170.             break;
  171.  
  172.         const grammar_t eg;
  173.         double          result;
  174.         iterator_t      iter    = str.begin();
  175.         iterator_t      end     = str.end();
  176.         bool            r       = qi::phrase_parse(iter, end, eg, ascii::space, result);
  177.  
  178.         if (r && iter == end) {
  179.             std::cout << "       \033[33m" << str << "\033[32m = " << result << "\033[0m" << std::endl;
  180.             return EXIT_SUCCESS;
  181.         }
  182.         else {
  183.             std::string padd(std::distance(iter, end), ' ');
  184.             std::cout << "\033[1;31merror:\033[0m " << str << '\n'
  185.                       << "       " << padd << "\033[32m^\033[0m" << std::endl;
  186.             return EXIT_FAILURE;
  187.         }
  188.     }
  189. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement