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 #include "ParseExp.h"
00028 
00029 #ifdef HAVE_CXX11
00030 // parser using shunting yard algorithm using C++11 features
00031 
00032 #include <exception>
00033 #include <stack>
00034 #include <queue>
00035 #include <functional>
00036 #define _USE_MATH_DEFINES
00037 #include <math.h>
00038 #include <cstdlib>
00039 
00040 namespace Parser
00041 {
00043 class ParseException : public std::runtime_error
00044 {
00045 public:
00046     explicit ParseException(const char *message) : std::runtime_error(message) {};
00047 };
00048 
00050 namespace RPNTokens
00051 {
00053 class TokenBase
00054 {
00055 public:
00056     virtual void evaluate(std::stack<double>&) = 0;
00057 };
00058 
00060 class NumericToken :public TokenBase
00061 {
00062 public:
00063     explicit NumericToken(double val) : m_value(val) {};
00064     void evaluate(std::stack<double>& rpnStack) { rpnStack.push(m_value); };
00065 private:
00066     double m_value;
00067 };
00068 
00070 class FunctionToken : public TokenBase
00071 {
00072 public:
00073     explicit FunctionToken(std::function<double(double)> func) : TokenBase(), m_function(func) {};
00074     void evaluate(std::stack<double>& rpnStack)
00075     {
00076         if (rpnStack.empty())
00077         {
00078             throw ParseException("Unary operator expects one item on stack.");
00079         }
00080         const double val = rpnStack.top();
00081         rpnStack.pop();
00082         const double newVal = m_function(val);
00083         if (!isinf(newVal) && !isnan(newVal))
00084         {
00085             rpnStack.push(newVal);
00086         }
00087         else
00088         {
00089             throw ParseException("Invalid operation");
00090         };
00091     };
00092 private:
00093     std::function<double(double)> m_function;
00094 };
00095 
00097 class BinaryToken : public TokenBase
00098 {
00099 public:
00100     explicit BinaryToken(std::function<double(double, double)> func) : TokenBase(), m_function(func) {};
00101     void evaluate(std::stack<double>& rpnStack)
00102     {
00103         if (rpnStack.size() < 2)
00104         {
00105             throw ParseException("BinaryOperator expects 2 items on stack.");
00106         };
00107         const double right = rpnStack.top();
00108         rpnStack.pop();
00109         const double left = rpnStack.top();
00110         rpnStack.pop();
00111         const double newVal = m_function(left, right);
00112         if (!isinf(newVal) && !isnan(newVal))
00113         {
00114             rpnStack.push(newVal);
00115         }
00116         else
00117         {
00118             throw ParseException("Invalid operation");
00119         };
00120     };
00121 private:
00122     std::function<double(double, double)> m_function;
00123 };
00124 
00126 class IfToken : public TokenBase
00127 {
00128 public:
00129     void evaluate(std::stack<double>& rpnStack)
00130     {
00131         if (rpnStack.size() < 3)
00132         {
00133             throw ParseException("IfOperator expects 3 items on stack.");
00134         };
00135         const double elseVal = rpnStack.top();
00136         rpnStack.pop();
00137         const double ifVal = rpnStack.top();
00138         rpnStack.pop();
00139         const double compareVal = rpnStack.top();
00140         rpnStack.pop();
00141         if (fabs(compareVal) > 1e-8)
00142         {
00143             rpnStack.push(ifVal);
00144         }
00145         else
00146         {
00147             rpnStack.push(elseVal);
00148         };
00149     };
00150 };
00151 } // namespace RPNTokens
00152 
00154 namespace Operators
00155 {
00157 class OperatorBase
00158 {
00159 public:
00160     OperatorBase(int prec, bool rightAssoc = false) : m_precedence(prec), m_rightAssoc(rightAssoc) {};
00161     const int GetPrecedence() const { return m_precedence; };
00162     const bool IsRightAssociative() const { return m_rightAssoc; };
00163     bool ComparePrecedence(const OperatorBase* other)
00164     {
00165         if (IsRightAssociative())
00166         {
00167             return GetPrecedence() < other->GetPrecedence();
00168         }
00169         else
00170         {
00171             return GetPrecedence() <= other->GetPrecedence();
00172         };
00173     };
00174     virtual RPNTokens::TokenBase* GetTokenBase() { return nullptr; };
00175 private:
00176     int m_precedence;
00177     bool m_rightAssoc;
00178 };
00179 
00181 class FunctionOperator : public OperatorBase
00182 {
00183 public:
00184     FunctionOperator(std::function<double(double)> func, int prec = -2, bool rightAssoc = false) : OperatorBase(prec, rightAssoc), m_function(func) {};
00185     RPNTokens::TokenBase* GetTokenBase() { return new RPNTokens::FunctionToken(m_function); };
00186 private:
00187     std::function<double(double)> m_function;
00188 };
00189 
00191 class BinaryOperator : public OperatorBase
00192 {
00193 public:
00194     BinaryOperator(std::function<double(double, double)> func, int prec, bool rightAssoc = false) : OperatorBase(prec, rightAssoc), m_function(func) {};
00195     RPNTokens::TokenBase* GetTokenBase() { return new RPNTokens::BinaryToken(m_function); };
00196 private:
00197     std::function<double(double, double)> m_function;
00198 };
00199 
00201 class IfOperator : public OperatorBase
00202 {
00203 public:
00204     IfOperator() : OperatorBase(0, true) {};
00205     RPNTokens::TokenBase* GetTokenBase() { return new RPNTokens::IfToken(); }
00206 };
00207 }; // namespace Operators
00208 
00210 void ClearQueue(std::queue<RPNTokens::TokenBase*>& input)
00211 {
00212     while (!input.empty())
00213     {
00214         delete input.front();
00215         input.pop();
00216     }
00217 }
00218 
00220 std::string RemoveWhiteSpaces(const std::string& text)
00221 {
00222     std::string output;
00223     output.reserve(text.size());
00224     for (auto c : text)
00225     {
00226         if (!isspace(c))
00227         {
00228             output.push_back(tolower(c));
00229         };
00230     };
00231     return output;
00232 };
00233 
00234 static std::map<std::string, Operators::OperatorBase*> supportedBinaryOperations;
00235 static Operators::OperatorBase* parenthesesOperator = nullptr;
00236 static Operators::OperatorBase* ifOperator = nullptr;
00237 static Operators::OperatorBase* ifOperatorClose = nullptr;
00238 static std::map<std::string, Operators::FunctionOperator*> supportedFunctions;
00239 
00241 void InitParser()
00242 {
00243     if (supportedBinaryOperations.empty())
00244     {
00245         supportedBinaryOperations["||"] = new Operators::BinaryOperator(std::logical_or<double>(), 2);
00246         supportedBinaryOperations["&&"] = new Operators::BinaryOperator(std::logical_and<double>(), 3);
00247         supportedBinaryOperations["=="] = new Operators::BinaryOperator(std::equal_to<double>(), 4);
00248         supportedBinaryOperations["!="] = new Operators::BinaryOperator(std::not_equal_to<double>(), 4);
00249         supportedBinaryOperations["<"] = new Operators::BinaryOperator(std::less<double>(), 5);
00250         supportedBinaryOperations["<="] = new Operators::BinaryOperator(std::less_equal<double>(), 5);
00251         supportedBinaryOperations[">"] = new Operators::BinaryOperator(std::greater<double>(), 5);
00252         supportedBinaryOperations[">="] = new Operators::BinaryOperator(std::greater_equal<double>(), 5);
00253         supportedBinaryOperations["+"] = new Operators::BinaryOperator(std::plus<double>(), 6);
00254         supportedBinaryOperations["-"] = new Operators::BinaryOperator(std::minus<double>(), 6);
00255         supportedBinaryOperations["*"] = new Operators::BinaryOperator(std::multiplies<double>(), 7);
00256         supportedBinaryOperations["/"] = new Operators::BinaryOperator(std::divides<double>(), 7);
00257         supportedBinaryOperations["%"] = new Operators::BinaryOperator((double(*)(double, double))fmod, 7);
00258         supportedBinaryOperations["^"] = new Operators::BinaryOperator((double(*)(double, double))pow, 8, true);
00259         supportedBinaryOperations["UNARY_MINUS"] = new Operators::FunctionOperator([](double val)->double {return -1 * val; }, 9, true);
00260     }
00261     if (!parenthesesOperator)
00262     {
00263         parenthesesOperator = new Operators::OperatorBase(-1);
00264     };
00265     if (!ifOperator)
00266     {
00267         ifOperator = new Operators::OperatorBase(1);
00268     }
00269     if (!ifOperatorClose)
00270     {
00271         ifOperatorClose = new Operators::IfOperator();
00272     }
00273     if (supportedFunctions.empty())
00274     {
00275         supportedFunctions["abs"] = new Operators::FunctionOperator((double(*)(double))abs);
00276         supportedFunctions["sin"] = new Operators::FunctionOperator((double(*)(double))sin);
00277         supportedFunctions["cos"] = new Operators::FunctionOperator((double(*)(double))cos);
00278         supportedFunctions["tan"] = new Operators::FunctionOperator((double(*)(double))tan);
00279         supportedFunctions["asin"] = new Operators::FunctionOperator((double(*)(double))asin);
00280         supportedFunctions["acos"] = new Operators::FunctionOperator((double(*)(double))acos);
00281         supportedFunctions["atan"] = new Operators::FunctionOperator((double(*)(double))atan);
00282         supportedFunctions["exp"] = new Operators::FunctionOperator((double(*)(double))exp);
00283         supportedFunctions["log"] = new Operators::FunctionOperator((double(*)(double))log);
00284         supportedFunctions["ceil"] = new Operators::FunctionOperator((double(*)(double))ceil);
00285         supportedFunctions["floor"] = new Operators::FunctionOperator((double(*)(double))floor);
00286         supportedFunctions["sqrt"] = new Operators::FunctionOperator((double(*)(double))sqrt);
00287         supportedFunctions["deg"] = new Operators::FunctionOperator([](double val)->double { return val * 180.0f / M_PI; });
00288         supportedFunctions["rad"] = new Operators::FunctionOperator([](double val)->double { return val * M_PI / 180.0f; });
00289     }
00290 };
00291 
00293 void CleanUpParser()
00294 {
00295     for (auto it : supportedBinaryOperations)
00296     {
00297         delete it.second;
00298     };
00299     supportedBinaryOperations.clear();
00300     for (auto it : supportedFunctions)
00301     {
00302         delete it.second;
00303     };
00304     supportedFunctions.clear();
00305     if (parenthesesOperator)
00306     {
00307         delete parenthesesOperator;
00308         parenthesesOperator = nullptr;
00309     };
00310     if (ifOperator)
00311     {
00312         delete ifOperator;
00313         ifOperator = nullptr;
00314     };
00315     if (ifOperatorClose)
00316     {
00317         delete ifOperatorClose;
00318         ifOperatorClose = nullptr;
00319     };
00320 };
00321 
00323 std::string FindOperator(const std::string& searchString)
00324 {
00325     std::string foundOperator;
00326     for (auto it : supportedBinaryOperations)
00327     {
00328         const std::string op(it.first);
00329         if (searchString.compare(0, op.length(), op) == 0)
00330         {
00331             if (op.length() > foundOperator.length())
00332             {
00333                 foundOperator = op;
00334             }
00335         };
00336     };
00337     return foundOperator;
00338 };
00339 
00342 bool ConvertToRPN(const std::string& expression, const ConstantMap& constants, std::queue<RPNTokens::TokenBase*>& rpn)
00343 {
00344     // initialize some internal variables, don't forget to call CleanUpParser() at the end
00345     InitParser();
00346     size_t pos = 0;
00347     std::stack<Operators::OperatorBase*> operatorStack;
00348     bool lastTokenWasOperator = true;
00349     const size_t expressionLength = expression.length();
00350     while (pos < expressionLength)
00351     {
00352         const char currentChar = expression[pos];
00353         if (lastTokenWasOperator && (currentChar == '+' || currentChar == '-'))
00354         {
00355             // special handling of +/- prefix
00356             if (currentChar == '-')
00357             {
00358                 operatorStack.push(supportedBinaryOperations["UNARY_MINUS"]);
00359             };
00360             pos++;
00361             lastTokenWasOperator = false;
00362             continue;
00363         }
00364         if (isdigit(currentChar) || currentChar == '.')
00365         {
00366             // parse numbers
00367             size_t index;
00368             double val;
00369             try
00370             {
00371                 val = std::stod(expression.substr(pos), &index);
00372             }
00373             catch (std::invalid_argument)
00374             {
00375                 throw ParseException("Invalid number");
00376             }
00377             catch (std::out_of_range)
00378             {
00379                 throw ParseException("Out of range");
00380             }
00381             index += pos;
00382             rpn.push(new RPNTokens::NumericToken(val));
00383             pos = index;
00384             lastTokenWasOperator = false;
00385             continue;
00386         }
00387         if (isalpha(currentChar))
00388         {
00389             // parse variable or function names
00390             const size_t found = expression.find_first_not_of("abcdefghijklmnopqrstuvwxyz0123456789_", pos);
00391             std::string subString;
00392             if (found != std::string::npos)
00393             {
00394                 subString = expression.substr(pos, found - pos);
00395                 // if next character is '(' we found a function name, otherwise we treat it as variable name
00396                 // all white space have been filtered out before
00397                 if (expression[found] == '(')
00398                 {
00399                     const auto foundFunction = supportedFunctions.find(subString);
00400                     if (foundFunction == supportedFunctions.end())
00401                     {
00402                         throw ParseException("Unknown function");
00403                     };
00404                     operatorStack.push(foundFunction->second);
00405                     operatorStack.push(parenthesesOperator);
00406                     pos = found + 1;
00407                     lastTokenWasOperator = true;
00408                     continue;
00409                 };
00410             }
00411             else
00412             {
00413                 // no further character in string, it can only be a variable name
00414                 subString = expression.substr(pos);
00415             };
00416             const auto foundVar = constants.find(subString);
00417             if (foundVar == constants.end())
00418             {
00419                 throw ParseException("Unknown variable");
00420             };
00421             rpn.push(new RPNTokens::NumericToken(foundVar->second));
00422             pos = found;
00423             lastTokenWasOperator = false;
00424             continue;
00425         };
00426         if (currentChar == '(')
00427         {
00428             // parse left parenthesis
00429             operatorStack.push(parenthesesOperator);
00430             pos++;
00431             lastTokenWasOperator = true;
00432             continue;
00433         };
00434         if (currentChar == ')')
00435         {
00436             // closing parenthesis
00437             bool matchingParenthesis = false;
00438             while (!operatorStack.empty())
00439             {
00440                 const int topPrecedenece = operatorStack.top()->GetPrecedence();
00441                 if (topPrecedenece == -2)
00442                 {
00443                     throw ParseException("Function without matching parenthesis");
00444                 }
00445                 if (topPrecedenece == -1)
00446                 {
00447                     // we found a matching parenthesis
00448                     matchingParenthesis = true;
00449                     operatorStack.pop();
00450                     break;
00451                 }
00452                 rpn.push(operatorStack.top()->GetTokenBase());
00453                 operatorStack.pop();
00454             }
00455             if (!matchingParenthesis)
00456             {
00457                 throw ParseException("Mismatched parentheses");
00458             };
00459             if (!operatorStack.empty() && operatorStack.top()->GetPrecedence() == -2)
00460             {
00461                 // we found a function on the operator stack
00462                 rpn.push(operatorStack.top()->GetTokenBase());
00463                 operatorStack.pop();
00464             };
00465             pos++;
00466             lastTokenWasOperator = false;
00467             continue;
00468         };
00469         if (currentChar == '?')
00470         {
00471             // we found an start of an ?: expression
00472             while (!operatorStack.empty() && operatorStack.top()->GetPrecedence() > 1)
00473             {
00474                 rpn.push(operatorStack.top()->GetTokenBase());
00475                 operatorStack.pop();
00476             };
00477             operatorStack.push(ifOperator);
00478             pos++;
00479             lastTokenWasOperator = true;
00480             continue;
00481         }
00482         if (currentChar == ':')
00483         {
00484             bool matchingIf = false;
00485             while (!operatorStack.empty())
00486             {
00487                 if (operatorStack.top()->GetPrecedence() == 1)
00488                 {
00489                     matchingIf = true;
00490                     operatorStack.pop();
00491                     break;
00492                 };
00493                 rpn.push(operatorStack.top()->GetTokenBase());
00494                 operatorStack.pop();
00495             }
00496             if (!matchingIf)
00497             {
00498                 throw ParseException("Mismatched ternary operator ?:");
00499             };
00500             operatorStack.push(ifOperatorClose);
00501             pos++;
00502             lastTokenWasOperator = true;
00503             continue;
00504         };
00505         // and finally the operators
00506         const std::string foundOperatorString = FindOperator(expression.substr(pos));
00507         if (foundOperatorString.empty())
00508         {
00509             throw ParseException("Invalid operator or unknown character");
00510         }
00511         Operators::OperatorBase* foundOperator = supportedBinaryOperations[foundOperatorString];
00512         while (!operatorStack.empty() && foundOperator->ComparePrecedence(operatorStack.top()))
00513         {
00514             rpn.push(operatorStack.top()->GetTokenBase());
00515             operatorStack.pop();
00516         };
00517         operatorStack.push(foundOperator);
00518         pos += foundOperatorString.length();
00519         lastTokenWasOperator = true;
00520     };
00521     while (!operatorStack.empty())
00522     {
00523         switch (operatorStack.top()->GetPrecedence())
00524         {
00525             case -2:
00526                 throw ParseException("Function with unbalanced parenthenses");
00527                 break;
00528             case -1:
00529                 throw ParseException("Unbalanced left and right parenthenses");
00530                 break;
00531             case 1:
00532                 throw ParseException("If without else");
00533                 break;
00534         }
00535         rpn.push(operatorStack.top()->GetTokenBase());
00536         operatorStack.pop();
00537     };
00538     return true;
00539 };
00540 
00543 bool EvaluateRPN(std::queue<RPNTokens::TokenBase*>& input, double& result)
00544 {
00545     std::stack<double> stack;
00546     try
00547     {
00548         while (!input.empty())
00549         {
00550             RPNTokens::TokenBase* token = input.front();
00551             token->evaluate(stack);
00552             delete token;
00553             input.pop();
00554         }
00555     }
00556     catch (ParseException)
00557     {
00558         ClearQueue(input);
00559         return false;
00560     };
00561     ClearQueue(input);
00562     if (stack.size() == 1)
00563     {
00564         result = stack.top();
00565         return true;
00566     }
00567     return false;
00568 };
00569 
00571 bool ParseExpression(const std::string& expression, double& result, const ConstantMap& constants)
00572 {
00573     std::queue<RPNTokens::TokenBase*> rpn;
00574     try
00575     {
00576         // remove all white spaces
00577         const std::string inputExpression = RemoveWhiteSpaces(expression);
00578         if (inputExpression.empty())
00579         {
00580             // if expression is now empty, return false
00581             return false;
00582         };
00583         ConstantMap inputConstants(constants);
00584         // add pi
00585         inputConstants["pi"] = M_PI;
00586         // convert expression to reverse polish notation rpn
00587         if (ConvertToRPN(inputExpression, inputConstants, rpn))
00588         {
00589             // if successful, evaluate queue
00590             return EvaluateRPN(rpn, result);
00591         }
00592         else
00593         {
00594             // could not convert to RPN
00595             ClearQueue(rpn);
00596             return false;
00597         };
00598     }
00599     catch (ParseException)
00600     {
00601         //something went wrong, delete queue and return false
00602         ClearQueue(rpn);
00603         return false;
00604     };
00605 };
00606 
00607 } //namespace Parser
00608 
00609 #else
00610 
00611 // implementation using boost::spirit is based on blog at
00612 // http://agentzlerich.blogspot.de/2011/06/using-boost-spirit-21-to-evaluate.html
00613 // modified to Hugins need
00614 // added if statement
00615 
00616 #include <limits>
00617 #include <iterator>
00618 
00619 #define BOOST_SPIRIT_USE_PHOENIX_V3 1
00620 #include <boost/spirit/version.hpp>
00621 #if !defined(SPIRIT_VERSION) || SPIRIT_VERSION < 0x2010
00622 #error "At least Spirit version 2.1 required"
00623 #endif
00624 #include <boost/math/constants/constants.hpp>
00625 #include <boost/spirit/include/phoenix.hpp>
00626 #include <boost/spirit/include/qi.hpp>
00627 
00628 namespace Parser
00629 {
00630 
00631 // helper classes to implement operators
00632 
00633 //power function
00634 struct lazy_pow_
00635 {
00636     typedef double result_type;
00637 
00638     double operator()(double x, double y) const
00639     {
00640         return std::pow(x, y);
00641     }
00642 };
00643 
00644 // modulus for double values
00645 struct lazy_mod_
00646 {
00647     typedef double result_type;
00648 
00649     double operator()(double x, double y) const
00650     {
00651         return std::fmod(x,y);
00652     }
00653 };
00654 
00655 // if statement
00656 struct lazy_if_
00657 {
00658     typedef double result_type;
00659 
00660     double operator()(double x, double y, double z) const
00661     {
00662         return (std::fabs(x)>1e-5) ? y : z;
00663     }
00664 };
00665 
00666 // wrapper for unary function
00667 struct lazy_ufunc_
00668 {
00669     typedef double result_type;
00670 
00671     double operator()(double (*f)(double), double a1) const
00672     {
00673         return f(a1);
00674     }
00675 };
00676 
00677 // convert rad into deg
00678 const double deg(const double d)
00679 {
00680     return d*180.0/boost::math::constants::pi<double>();
00681 };
00682 
00683 // convert deg into rad
00684 const double rad(const double d)
00685 {
00686     return d*boost::math::constants::pi<double>()/180;
00687 };
00688 
00689 // the main grammar class
00690 struct grammar:boost::spirit::qi::grammar<std::string::const_iterator, double(), boost::spirit::ascii::space_type>
00691 {
00692 
00693     // symbol table for constants like "pi", e.g. image number and value
00694     struct constant_ : boost::spirit::qi::symbols<char, double>
00695     {
00696         constant_(const ConstantMap constMap)
00697         {
00698             this->add("pi", boost::math::constants::pi<double>());
00699             if (constMap.size()>0)
00700             {
00701                 for (ConstantMap::const_iterator it = constMap.begin(); it != constMap.end(); it++)
00702                 {
00703                     this->add(it->first, it->second);
00704                 };
00705             };
00706         };
00707     };
00708 
00709     // symbol table for unary functions like "abs"
00710     struct ufunc_ : boost::spirit::qi::symbols<char, double(*)(double) >
00711     {
00712         ufunc_()
00713         {
00714             this->add
00715                 ("abs", (double(*)(double)) std::abs)
00716                 ("acos", (double(*)(double)) std::acos)
00717                 ("asin", (double(*)(double)) std::asin)
00718                 ("atan", (double(*)(double)) std::atan)
00719                 ("ceil", (double(*)(double)) std::ceil)
00720                 ("sin", (double(*)(double)) std::sin)
00721                 ("cos", (double(*)(double)) std::cos)
00722                 ("tan", (double(*)(double)) std::tan)
00723                 ("exp", (double(*)(double)) std::exp)
00724                 ("floor", (double(*)(double)) std::floor)
00725                 ("sqrt", (double(*)(double)) std::sqrt)
00726                 ("deg", (double(*)(double)) deg)
00727                 ("rad", (double(*)(double)) rad)
00728                 ;
00729         }
00730     } ufunc;
00731 
00732     boost::spirit::qi::rule<std::string::const_iterator, double(), boost::spirit::ascii::space_type> expression, term, factor, primary, compExpression, compTerm, numExpression;
00733 
00734     grammar(const ConstantMap constMap) : grammar::base_type(expression)
00735     {
00736         using boost::spirit::qi::real_parser;
00737         using boost::spirit::qi::real_policies;
00738         real_parser<double, real_policies<double> > real;
00739 
00740         using boost::spirit::qi::_1;
00741         using boost::spirit::qi::_2;
00742         using boost::spirit::qi::_3;
00743         using boost::spirit::qi::no_case;
00744         using boost::spirit::qi::_val;
00745         struct constant_ constant(constMap);
00746 
00747         boost::phoenix::function<lazy_pow_>   lazy_pow;
00748         boost::phoenix::function<lazy_mod_>   lazy_mod;
00749         boost::phoenix::function<lazy_if_>    lazy_if;
00750         boost::phoenix::function<lazy_ufunc_> lazy_ufunc;
00751 
00752         expression =
00753             (compExpression >> '\?' >> compExpression >> ':' >> compExpression)[_val = lazy_if(_1, _2, _3)]
00754             | compExpression[_val = _1]
00755             ;
00756 
00757         compExpression =
00758             compTerm[_val = _1]
00759             >> *(("&&" >> compTerm[_val = _val && _1])
00760             | ("||" >> compTerm[_val = _val || _1])
00761             )
00762             ;
00763 
00764         compTerm =
00765             numExpression[_val = _1]
00766             >> *(('<' >> numExpression[_val = _val <  _1])
00767             | ('>' >> numExpression[_val = _val >  _1])
00768             | ("<=" >> numExpression[_val = _val <= _1])
00769             | (">=" >> numExpression[_val = _val >= _1])
00770             | ("==" >> numExpression[_val = _val == _1])
00771             | ("!=" >> numExpression[_val = _val != _1])
00772             )
00773             ;
00774 
00775         numExpression =
00776             term[_val = _1]
00777             >> *(('+' >> term[_val += _1])
00778             | ('-' >> term[_val -= _1])
00779             )
00780             ;
00781 
00782         term =
00783             factor[_val = _1]
00784             >> *(('*' >> factor[_val *= _1])
00785             | ('/' >> factor[_val /= _1])
00786             | ('%' >> factor[_val = lazy_mod(_val, _1)])
00787             )
00788             ;
00789 
00790         factor =
00791             primary[_val = _1]
00792             >> *(('^' >> factor[_val = lazy_pow(_val, _1)]))
00793             ;
00794 
00795         primary =
00796             real[_val = _1]
00797             | '(' >> expression[_val = _1] >> ')'
00798             | ('-' >> primary[_val = -_1])
00799             | ('+' >> primary[_val = _1])
00800             | no_case[constant][_val = _1]
00801             | (no_case[ufunc] >> '(' >> expression >> ')')[_val = lazy_ufunc(_1, _2)]
00802             ;
00803 
00804     };
00805 };
00806 
00807 bool parse(std::string::const_iterator& iter,
00808            std::string::const_iterator end,
00809            const grammar& g,
00810            double& result)
00811 {
00812     if(!boost::spirit::qi::phrase_parse(iter, end, g, boost::spirit::ascii::space, result))
00813     {
00814         return false;
00815     };
00816     // we check if the full string could parsed
00817     return iter==end;
00818 }
00819 
00820 // version with pre-defined constants
00821 bool ParseExpression(const std::string& expression, double& result, const ConstantMap& constants)
00822 {
00823     grammar g(constants);
00824     std::string::const_iterator it=expression.begin();
00825     return parse(it, expression.end(), g, result);
00826 };
00827 
00828 void CleanUpParser()
00829 {
00830 };
00831 
00832 } // namespace
00833 #endif

Generated on 13 Feb 2016 for Hugintrunk by  doxygen 1.4.7