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, write to the Free Software
00023  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 #include <boost/spirit/version.hpp>
00038 #if !defined(SPIRIT_VERSION) || SPIRIT_VERSION < 0x2010
00039 #error "At least Spirit version 2.1 required"
00040 #endif
00041 #include <boost/math/constants/constants.hpp>
00042 #include <boost/spirit/include/phoenix.hpp>
00043 #include <boost/spirit/include/qi.hpp>
00044 
00045 namespace Parser
00046 {
00047 
00048 // helper classes to implement operators
00049 
00050 //power function
00051 struct lazy_pow_
00052 {
00053     template <typename X, typename Y>
00054     struct result { typedef X type; };
00055 
00056     template <typename X, typename Y>
00057     X operator()(X x, Y y) const
00058     {
00059         return std::pow(x, y);
00060     }
00061 };
00062 
00063 // modulus for double values
00064 struct lazy_mod_
00065 {
00066     template <typename X, typename Y>
00067     struct result { typedef X type; };
00068 
00069     template <typename X, typename Y>
00070     X operator()(X x, Y y) const
00071     {
00072         return std::fmod(x,y);
00073     }
00074 };
00075 
00076 // if statement
00077 struct lazy_if_
00078 {
00079     template <typename X, typename Y, typename Z>
00080     struct result { typedef Y type; };
00081 
00082     template <typename X, typename Y, typename Z>
00083     X operator()(X x, Y y, Z z) const
00084     {
00085         return x ? y : z;
00086     }
00087 };
00088 
00089 // wrapper for unary function
00090 struct lazy_ufunc_
00091 {
00092     template <typename F, typename A1>
00093     struct result { typedef A1 type; };
00094 
00095     template <typename F, typename A1>
00096     A1 operator()(F f, A1 a1) const
00097     {
00098         return f(a1);
00099     }
00100 };
00101 
00102 // convert rad into deg
00103 double deg(const double d)
00104 {
00105     return d*180.0/boost::math::constants::pi<double>();
00106 };
00107 
00108 // convert deg into rad
00109 double rad(const double d)
00110 {
00111     return d*boost::math::constants::pi<double>()/180;
00112 };
00113 
00114 // the main grammar class
00115 struct grammar:boost::spirit::qi::grammar<std::string::const_iterator, double(), boost::spirit::ascii::space_type>
00116 {
00117 
00118     // symbol table for constants like "pi", e.g. image number and value
00119     struct constant_ : boost::spirit::qi::symbols<char, double>
00120     {
00121         constant_(const ConstantMap constMap)
00122         {
00123             this->add("pi", boost::math::constants::pi<double>());
00124             if(constMap.size()>0)
00125             {
00126                 for(ConstantMap::const_iterator it=constMap.begin(); it!=constMap.end(); it++)
00127                 {
00128                     this->add(it->first, it->second); 
00129                 };
00130             };
00131         };
00132     };
00133 
00134     // symbol table for unary functions like "abs"
00135     struct ufunc_  : boost::spirit::qi::symbols<char, double(*)(double) >
00136     {
00137         ufunc_()
00138         {
00139             this->add
00140                 ("abs"   , (double (*)(double)) std::abs  )
00141                 ("acos"  , (double (*)(double)) std::acos )
00142                 ("asin"  , (double (*)(double)) std::asin )
00143                 ("atan"  , (double (*)(double)) std::atan )
00144                 ("ceil"  , (double (*)(double)) std::ceil )
00145                 ("sin"   , (double (*)(double)) std::sin  )
00146                 ("cos"   , (double (*)(double)) std::cos  )
00147                 ("tan"   , (double (*)(double)) std::tan  )
00148                 ("exp"   , (double (*)(double)) std::exp  )
00149                 ("floor" , (double (*)(double)) std::floor)
00150                 ("sqrt"  , (double (*)(double)) std::sqrt )
00151                 ("deg"   , (double (*)(double)) deg  )
00152                 ("rad"   , (double (*)(double)) rad  )
00153             ;
00154         }
00155     } ufunc;
00156 
00157     boost::spirit::qi::rule<std::string::const_iterator, double(), boost::spirit::ascii::space_type> expression, term, factor, primary, compExpression, compTerm, numExpression;
00158 
00159     grammar(const ConstantMap constMap) : grammar::base_type(expression)
00160     {
00161         using boost::spirit::qi::real_parser;
00162         using boost::spirit::qi::real_policies;
00163         real_parser<double,real_policies<double> > real;
00164 
00165         using boost::spirit::qi::_1;
00166         using boost::spirit::qi::_2;
00167         using boost::spirit::qi::_3;
00168         using boost::spirit::qi::no_case;
00169         using boost::spirit::qi::_val;
00170         struct constant_ constant(constMap);
00171 
00172         boost::phoenix::function<lazy_pow_>   lazy_pow;
00173         boost::phoenix::function<lazy_mod_>   lazy_mod;
00174         boost::phoenix::function<lazy_if_>    lazy_if;
00175         boost::phoenix::function<lazy_ufunc_> lazy_ufunc;
00176 
00177         expression = 
00178             (compExpression >> '\?' >> compExpression >> ':' >> compExpression) [_val = lazy_if(_1, _2, _3)]
00179             | compExpression [_val=_1]
00180             ;
00181         
00182         compExpression=
00183             compTerm  [_val=_1]
00184             >> * ( ("&&" >> compTerm [_val = _val && _1] )
00185                   |("||" >> compTerm [_val = _val || _1] )
00186                  )
00187             ;
00188 
00189         compTerm =
00190             numExpression                [_val = _1        ]
00191             >>*( ( '<'  >> numExpression [_val = _val <  _1])
00192                 |( '>'  >> numExpression [_val = _val >  _1])
00193                 |( "<=" >> numExpression [_val = _val <= _1])
00194                 |( ">=" >> numExpression [_val = _val >= _1])
00195                 |( "==" >> numExpression [_val = _val == _1])
00196                 |( "!=" >> numExpression [_val = _val != _1])
00197                )
00198             ;
00199 
00200         numExpression =
00201             term                   [_val =  _1]
00202             >> *(  ('+' >> term    [_val += _1])
00203                 |  ('-' >> term    [_val -= _1])
00204                 )
00205             ;
00206 
00207         term =
00208             factor                 [_val =  _1]
00209             >> *(  ('*' >> factor  [_val *= _1])
00210                 |  ('/' >> factor  [_val /= _1])
00211                 |  ('%' >> factor  [_val = lazy_mod(_val, _1)])
00212                 )
00213             ;
00214 
00215         factor =
00216             primary                [_val =  _1]
00217             >> *(  ('^' >> factor [_val = lazy_pow(_val, _1)]) )
00218             ;
00219 
00220         primary =
00221             real                   [_val =  _1]
00222             |  '(' >> expression   [_val =  _1] >> ')'
00223             |  ('-' >> primary     [_val = -_1])
00224             |  ('+' >> primary     [_val =  _1])
00225             |  no_case[constant]   [_val =  _1]
00226             |  (no_case[ufunc] >> '(' >> expression >> ')') [_val = lazy_ufunc(_1, _2) ]
00227             ;
00228 
00229     };
00230 };
00231 
00232 //template <typename ParserType, typename Iterator>
00233 bool parse(std::string::const_iterator &iter,
00234            std::string::const_iterator end,
00235            const grammar &g,
00236            double& result)
00237 {
00238     if(!boost::spirit::qi::phrase_parse(iter, end, g, boost::spirit::ascii::space, result))
00239     {
00240         return false;
00241     };
00242     // we check if the full string could parsed
00243     return iter==end;
00244 }
00245 
00246 // the function which exposes the interface to external
00247 // version without pre-defined constants 
00248 bool ParseExpression(const std::string expression, double& result)
00249 {
00250     ConstantMap constants;
00251     return ParseExpression(expression, result, constants);
00252 };
00253     
00254 // version with pre-defined constants
00255 bool ParseExpression(const std::string expression, double& result, const ConstantMap constants)
00256 {
00257     grammar g(constants);
00258     std::string::const_iterator it=expression.begin();
00259     return parse(it, expression.end(), g, result);
00260 };
00261 
00262 } // namespace

Generated on Thu Apr 24 01:25:40 2014 for Hugintrunk by  doxygen 1.3.9.1