/* * LLCalcParser.h * Copyright 2008 Aimee Walton. * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2008, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * */ #ifndef LL_CALCPARSER_H #define LL_CALCPARSER_H #include #if !defined(SPIRIT_VERSION) || SPIRIT_VERSION < 0x2010 #error "At least Spirit version 2.1 required" #endif // Add this in if we want boost math constants. //#include #include #include namespace expression { //TODO: If we can find a better way to do this with boost::pheonix::bind lets do it //namespace { // anonymous template T min_glue(T a, T b) { return std::min(a, b); } template T max_glue(T a, T b) { return std::max(a, b); } struct lazy_pow_ { template struct result { typedef X type; }; template X operator()(X x, Y y) const { return std::pow(x, y); } }; struct lazy_ufunc_ { template struct result { typedef A1 type; }; template A1 operator()(F f, A1 a1) const { return f(a1); } }; struct lazy_bfunc_ { template struct result { typedef A1 type; }; template A1 operator()(F f, A1 a1, A2 a2) const { return f(a1, a2); } }; //} // end namespace anonymous template struct grammar : boost::spirit::qi::grammar< Iterator, FPT(), boost::spirit::ascii::space_type > { // symbol table for constants // to be added by the actual calculator struct constant_ : boost::spirit::qi::symbols< typename std::iterator_traits::value_type, FPT > { constant_() { } } constant; // symbol table for unary functions like "abs" struct ufunc_ : boost::spirit::qi::symbols< typename std::iterator_traits::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) ("log" , (FPT (*)(FPT)) std::log ) ("log10" , (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::value_type, FPT (*)(FPT, FPT) > { bfunc_() { using boost::bind; this->add ("pow" , (FPT (*)(FPT, FPT)) std::pow ) ("atan2", (FPT (*)(FPT, FPT)) std::atan2) ("min" , (FPT (*)(FPT, FPT)) min_glue) ("max" , (FPT (*)(FPT, FPT)) max_glue) ; } } bfunc; boost::spirit::qi::rule< Iterator, FPT(), boost::spirit::ascii::space_type > expression, term, factor, primary; grammar() : grammar::base_type(expression) { using boost::spirit::qi::real_parser; using boost::spirit::qi::real_policies; real_parser > real; using boost::spirit::qi::_1; using boost::spirit::qi::_2; using boost::spirit::qi::_3; using boost::spirit::qi::no_case; using boost::spirit::qi::_val; boost::phoenix::function lazy_pow; boost::phoenix::function lazy_ufunc; boost::phoenix::function 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[ufunc] >> '(' >> expression >> ')') [_val = lazy_ufunc(_1, _2)] | (no_case[bfunc] >> '(' >> expression >> ',' >> expression >> ')') [_val = lazy_bfunc(_1, _2, _3)] | no_case[constant] [_val = _1] ; } }; template bool parse(Iterator &iter, Iterator end, const grammar &g, FPT &result) { return boost::spirit::qi::phrase_parse( iter, end, g, boost::spirit::ascii::space, result); } } // end namespace expression #endif // LL_CALCPARSER_H