ParseExp.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00011 /*  This program is free software; you can redistribute it and/or
00012  *  modify it under the terms of the GNU General Public
00013  *  License as published by the Free Software Foundation; either
00014  *  version 2 of the License, or (at your option) any later version.
00015  *
00016  *  This software is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public
00022  *  License along with this software. If not, see
00023  *  <http://www.gnu.org/licenses/>.
00024  *
00025  */
00026 
00027 // implementation is based on blog at
00028 // http://agentzlerich.blogspot.de/2011/06/using-boost-spirit-21-to-evaluate.html
00029 // modified to Hugins need
00030 // added if statement
00031 
00032 #include "ParseExp.h"
00033 
00034 #include <limits>
00035 #include <iterator>
00036 
00037 #define BOOST_SPIRIT_USE_PHOENIX_V3 1
00038 #include <boost/spirit/version.hpp>
00039 #if !defined(SPIRIT_VERSION) || SPIRIT_VERSION < 0x2010
00040 #error "At least Spirit version 2.1 required"
00041 #endif
00042 #include <boost/math/constants/constants.hpp>
00043 #include <boost/spirit/include/phoenix.hpp>
00044 #include <boost/spirit/include/qi.hpp>
00045 
00046 namespace Parser
00047 {
00048 
00049 // helper classes to implement operators
00050 
00051 //power function
00052 struct lazy_pow_
00053 {
00054     typedef double result_type;
00055 
00056     double operator()(double x, double y) const
00057     {
00058         return std::pow(x, y);
00059     }
00060 };
00061 
00062 // modulus for double values
00063 struct lazy_mod_
00064 {
00065     typedef double result_type;
00066 
00067     double operator()(double x, double y) const
00068     {
00069         return std::fmod(x,y);
00070     }
00071 };
00072 
00073 // if statement
00074 struct lazy_if_
00075 {
00076     typedef double result_type;
00077 
00078     double operator()(double x, double y, double z) const
00079     {
00080         return (std::fabs(x)>1e-5) ? y : z;
00081     }
00082 };
00083 
00084 // wrapper for unary function
00085 struct lazy_ufunc_
00086 {
00087     typedef double result_type;
00088 
00089     double operator()(double (*f)(double), double a1) const
00090     {
00091         return f(a1);
00092     }
00093 };
00094 
00095 // convert rad into deg
00096 const double deg(const double d)
00097 {
00098     return d*180.0/boost::math::constants::pi<double>();
00099 };
00100 
00101 // convert deg into rad
00102 const double rad(const double d)
00103 {
00104     return d*boost::math::constants::pi<double>()/180;
00105 };
00106 
00107 // the main grammar class
00108 struct grammar:boost::spirit::qi::grammar<std::string::const_iterator, double(), boost::spirit::ascii::space_type>
00109 {
00110 
00111     // symbol table for constants like "pi", e.g. image number and value
00112     struct constant_ : boost::spirit::qi::symbols<char, double>
00113     {
00114         constant_(const ConstantMap constMap)
00115         {
00116             this->add("pi", boost::math::constants::pi<double>());
00117             if (constMap.size()>0)
00118             {
00119                 for (ConstantMap::const_iterator it = constMap.begin(); it != constMap.end(); it++)
00120                 {
00121                     this->add(it->first, it->second);
00122                 };
00123             };
00124         };
00125     };
00126 
00127     // symbol table for unary functions like "abs"
00128     struct ufunc_ : boost::spirit::qi::symbols<char, double(*)(double) >
00129     {
00130         ufunc_()
00131         {
00132             this->add
00133                 ("abs", (double(*)(double)) std::abs)
00134                 ("acos", (double(*)(double)) std::acos)
00135                 ("asin", (double(*)(double)) std::asin)
00136                 ("atan", (double(*)(double)) std::atan)
00137                 ("ceil", (double(*)(double)) std::ceil)
00138                 ("sin", (double(*)(double)) std::sin)
00139                 ("cos", (double(*)(double)) std::cos)
00140                 ("tan", (double(*)(double)) std::tan)
00141                 ("exp", (double(*)(double)) std::exp)
00142                 ("floor", (double(*)(double)) std::floor)
00143                 ("sqrt", (double(*)(double)) std::sqrt)
00144                 ("deg", (double(*)(double)) deg)
00145                 ("rad", (double(*)(double)) rad)
00146                 ;
00147         }
00148     } ufunc;
00149 
00150     boost::spirit::qi::rule<std::string::const_iterator, double(), boost::spirit::ascii::space_type> expression, term, factor, primary, compExpression, compTerm, numExpression;
00151 
00152     grammar(const ConstantMap constMap) : grammar::base_type(expression)
00153     {
00154         using boost::spirit::qi::real_parser;
00155         using boost::spirit::qi::real_policies;
00156         real_parser<double, real_policies<double> > real;
00157 
00158         using boost::spirit::qi::_1;
00159         using boost::spirit::qi::_2;
00160         using boost::spirit::qi::_3;
00161         using boost::spirit::qi::no_case;
00162         using boost::spirit::qi::_val;
00163         struct constant_ constant(constMap);
00164 
00165         boost::phoenix::function<lazy_pow_>   lazy_pow;
00166         boost::phoenix::function<lazy_mod_>   lazy_mod;
00167         boost::phoenix::function<lazy_if_>    lazy_if;
00168         boost::phoenix::function<lazy_ufunc_> lazy_ufunc;
00169 
00170         expression =
00171             (compExpression >> '\?' >> compExpression >> ':' >> compExpression)[_val = lazy_if(_1, _2, _3)]
00172             | compExpression[_val = _1]
00173             ;
00174 
00175         compExpression =
00176             compTerm[_val = _1]
00177             >> *(("&&" >> compTerm[_val = _val && _1])
00178             | ("||" >> compTerm[_val = _val || _1])
00179             )
00180             ;
00181 
00182         compTerm =
00183             numExpression[_val = _1]
00184             >> *(('<' >> numExpression[_val = _val <  _1])
00185             | ('>' >> numExpression[_val = _val >  _1])
00186             | ("<=" >> numExpression[_val = _val <= _1])
00187             | (">=" >> numExpression[_val = _val >= _1])
00188             | ("==" >> numExpression[_val = _val == _1])
00189             | ("!=" >> numExpression[_val = _val != _1])
00190             )
00191             ;
00192 
00193         numExpression =
00194             term[_val = _1]
00195             >> *(('+' >> term[_val += _1])
00196             | ('-' >> term[_val -= _1])
00197             )
00198             ;
00199 
00200         term =
00201             factor[_val = _1]
00202             >> *(('*' >> factor[_val *= _1])
00203             | ('/' >> factor[_val /= _1])
00204             | ('%' >> factor[_val = lazy_mod(_val, _1)])
00205             )
00206             ;
00207 
00208         factor =
00209             primary[_val = _1]
00210             >> *(('^' >> factor[_val = lazy_pow(_val, _1)]))
00211             ;
00212 
00213         primary =
00214             real[_val = _1]
00215             | '(' >> expression[_val = _1] >> ')'
00216             | ('-' >> primary[_val = -_1])
00217             | ('+' >> primary[_val = _1])
00218             | no_case[constant][_val = _1]
00219             | (no_case[ufunc] >> '(' >> expression >> ')')[_val = lazy_ufunc(_1, _2)]
00220             ;
00221 
00222     };
00223 };
00224 
00225 bool parse(std::string::const_iterator& iter,
00226            std::string::const_iterator end,
00227            const grammar& g,
00228            double& result)
00229 {
00230     if(!boost::spirit::qi::phrase_parse(iter, end, g, boost::spirit::ascii::space, result))
00231     {
00232         return false;
00233     };
00234     // we check if the full string could parsed
00235     return iter==end;
00236 }
00237 
00238 // version with pre-defined constants
00239 bool ParseExpression(const std::string& expression, double& result, const ConstantMap& constants)
00240 {
00241     grammar g(constants);
00242     std::string::const_iterator it=expression.begin();
00243     return parse(it, expression.end(), g, result);
00244 };
00245 
00246 } // namespace

Generated on 31 Aug 2015 for Hugintrunk by  doxygen 1.4.7