Skip to content
Snippets Groups Projects
Commit e30d5060 authored by Rye Mutt's avatar Rye Mutt :bread:
Browse files

Replace LLCalc code with alchemy version

parent 4d899ea4
No related branches found
No related tags found
No related merge requests found
......@@ -28,70 +28,67 @@
#include "llcalc.h"
#include "llcalcparser.h"
#include "llmath.h"
#include "llcalcparser.h"
// Variable names for use in the build floater
const char* LLCalc::X_POS = "PX";
const char* LLCalc::Y_POS = "PY";
const char* LLCalc::Z_POS = "PZ";
const char* LLCalc::X_SCALE = "SX";
const char* LLCalc::Y_SCALE = "SY";
const char* LLCalc::Z_SCALE = "SZ";
const char* LLCalc::X_ROT = "RX";
const char* LLCalc::Y_ROT = "RY";
const char* LLCalc::Z_ROT = "RZ";
const char* LLCalc::HOLLOW = "HLW";
const char* LLCalc::CUT_BEGIN = "CB";
const char* LLCalc::CUT_END = "CE";
const char* LLCalc::PATH_BEGIN = "PB";
const char* LLCalc::PATH_END = "PE";
const char* LLCalc::TWIST_BEGIN = "TB";
const char* LLCalc::TWIST_END = "TE";
const char* LLCalc::X_SHEAR = "SHX";
const char* LLCalc::Y_SHEAR = "SHY";
const char* LLCalc::X_TAPER = "TPX";
const char* LLCalc::Y_TAPER = "TPY";
const char* LLCalc::RADIUS_OFFSET = "ROF";
const char* LLCalc::REVOLUTIONS = "REV";
const char* LLCalc::SKEW = "SKW";
const char* LLCalc::X_HOLE = "HLX";
const char* LLCalc::Y_HOLE = "HLY";
const char* LLCalc::TEX_U_SCALE = "TSU";
const char* LLCalc::TEX_V_SCALE = "TSV";
const char* LLCalc::TEX_U_OFFSET = "TOU";
const char* LLCalc::TEX_V_OFFSET = "TOV";
const char* LLCalc::TEX_ROTATION = "TROT";
const char* LLCalc::TEX_TRANSPARENCY = "TRNS";
const char* LLCalc::TEX_GLOW = "GLOW";
LLCalc* LLCalc::sInstance = NULL;
const char* LLCalc::X_POS = "px";
const char* LLCalc::Y_POS = "py";
const char* LLCalc::Z_POS = "pz";
const char* LLCalc::X_SCALE = "sx";
const char* LLCalc::Y_SCALE = "sy";
const char* LLCalc::Z_SCALE = "sz";
const char* LLCalc::X_ROT = "rx";
const char* LLCalc::Y_ROT = "ry";
const char* LLCalc::Z_ROT = "rz";
const char* LLCalc::HOLLOW = "hlw";
const char* LLCalc::CUT_BEGIN = "cb";
const char* LLCalc::CUT_END = "ce";
const char* LLCalc::PATH_BEGIN = "pb";
const char* LLCalc::PATH_END = "pe";
const char* LLCalc::TWIST_BEGIN = "tb";
const char* LLCalc::TWIST_END = "te";
const char* LLCalc::X_SHEAR = "shx";
const char* LLCalc::Y_SHEAR = "shy";
const char* LLCalc::X_TAPER = "tpx";
const char* LLCalc::Y_TAPER = "tpy";
const char* LLCalc::RADIUS_OFFSET = "rof";
const char* LLCalc::REVOLUTIONS = "rev";
const char* LLCalc::SKEW = "skw";
const char* LLCalc::X_HOLE = "hlx";
const char* LLCalc::Y_HOLE = "hly";
const char* LLCalc::TEX_U_SCALE = "tsu";
const char* LLCalc::TEX_V_SCALE = "tsv";
const char* LLCalc::TEX_U_OFFSET = "tou";
const char* LLCalc::TEX_V_OFFSET = "tov";
const char* LLCalc::TEX_ROTATION = "trot";
const char* LLCalc::TEX_TRANSPARENCY = "trns";
const char* LLCalc::TEX_GLOW = "glow";
LLCalc* LLCalc::sInstance = nullptr;
LLCalc::LLCalc() : mLastErrorPos(0)
{
// Init table of constants
mConstants["PI"] = F_PI;
mConstants["TWO_PI"] = F_TWO_PI;
mConstants["PI_BY_TWO"] = F_PI_BY_TWO;
mConstants["SQRT_TWO_PI"] = F_SQRT_TWO_PI;
mConstants["SQRT2"] = F_SQRT2;
mConstants["SQRT3"] = F_SQRT3;
mConstants["DEG_TO_RAD"] = DEG_TO_RAD;
mConstants["RAD_TO_DEG"] = RAD_TO_DEG;
mConstants["GRAVITY"] = GRAVITY;
/*setVar("PI", F_PI);
setVar("TWO_PI", F_TWO_PI);
setVar("PI_BY_TWO", F_PI_BY_TWO);
setVar("SQRT_TWO_PI", F_SQRT_TWO_PI);
setVar("SQRT2", F_SQRT2);
setVar("SQRT3", F_SQRT3);
setVar("DEG_TO_RAD", DEG_TO_RAD);
setVar("RAD_TO_DEG", RAD_TO_DEG);
setVar("GRAVITY", GRAVITY);*/
}
LLCalc::~LLCalc()
{
}
//static
void LLCalc::cleanUp()
{
delete sInstance;
sInstance = NULL;
sInstance = nullptr;
}
//static
......@@ -129,34 +126,36 @@ void LLCalc::updateVariables(LLSD& vars)
bool LLCalc::evalString(const std::string& expression, F32& result)
{
std::string expr_upper = expression;
LLStringUtil::toUpper(expr_upper);
LLCalcParser calc(result, &mConstants, &mVariables);
mLastErrorPos = 0;
std::string::iterator start = expr_upper.begin();
parse_info<std::string::iterator> info;
try
std::string::const_iterator itr = expression.begin();
expression::grammar<F32,std::string::const_iterator> calc;
calc.constant.add
("pi", F_PI)
("two_pi", F_TWO_PI)
("pi_by_two", F_PI_BY_TWO)
("sqrt_two_pi", F_SQRT_TWO_PI)
("sqrt2", F_SQRT2)
("sqrt3", F_SQRT3)
("deg_to_rad", DEG_TO_RAD)
("rad_to_deg", RAD_TO_DEG)
("gravity", GRAVITY)
;
for(calc_map_t::const_iterator iter = mVariables.begin();
iter != mVariables.end();
++iter)
{
info = parse(start, expr_upper.end(), calc, space_p);
LL_DEBUGS() << "Math expression: " << expression << " = " << result << LL_ENDL;
}
catch(parser_error<std::string, std::string::iterator> &e)
{
mLastErrorPos = e.where - expr_upper.begin();
calc.constant.add(iter->first, iter->second);
LL_INFOS() << "Calc parser exception: " << e.descriptor << " at " << mLastErrorPos << " in expression: " << expression << LL_ENDL;
return false;
}
if (!info.full)
if (!expression::parse<F32,std::string::const_iterator>(itr, expression.end(), calc, result) || itr != expression.end())
{
mLastErrorPos = info.stop - expr_upper.begin();
mLastErrorPos = itr - expression.begin();
LL_INFOS() << "Unhandled syntax error at " << mLastErrorPos << " in expression: " << expression << LL_ENDL;
return false;
}
LL_DEBUGS() << "Math expression: " << expression << " = " << result << LL_ENDL;
return true;
}
......@@ -34,7 +34,7 @@ class LLCalc
{
public:
LLCalc();
~LLCalc();
~LLCalc() = default;
// Variable name constants
static const char* X_POS;
......@@ -86,13 +86,8 @@ class LLCalc
private:
std::string::size_type mLastErrorPos;
calc_map_t mConstants;
calc_map_t mVariables;
// *TODO: Add support for storing user defined variables, and stored functions.
// Will need UI work, and a means to save them between sessions.
// calc_map_t mUserVariables;
// "There shall be only one"
static LLCalc* sInstance;
};
......
/*
* LLCalcParser.cpp
* 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$
*
*/
#include "linden_common.h"
#include "llcalcparser.h"
using namespace boost::spirit::classic;
F32 LLCalcParser::lookup(const std::string::iterator& start, const std::string::iterator& end) const
{
LLCalc::calc_map_t::iterator iter;
std::string name(start, end);
if (mConstants)
{
iter = mConstants->find(name);
if (iter != mConstants->end())
{
return (*iter).second;
}
}
else
{
// This should never happen!
throw_(end, std::string("Missing constants table"));
}
if (mVariables)
{
iter = mVariables->find(name);
if (iter != mVariables->end())
{
return (*iter).second;
}
}
throw_(end, std::string("Unknown symbol " + name));
return 0.f;
}
......@@ -27,162 +27,208 @@
#ifndef LL_CALCPARSER_H
#define LL_CALCPARSER_H
#include <boost/spirit/include/classic_attribute.hpp>
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_error_handling.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp>
#include <boost/spirit/include/phoenix1_binders.hpp>
#include <boost/spirit/include/classic_symbols.hpp>
using namespace boost::spirit::classic;
#include <boost/spirit/version.hpp>
#if !defined(SPIRIT_VERSION) || SPIRIT_VERSION < 0x2010
#error "At least Spirit version 2.1 required"
#endif
#include "llcalc.h"
#include "llmath.h"
// Add this in if we want boost math constants.
#include <boost/bind.hpp>
//#include <boost/math/constants/constants.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
struct LLCalcParser : grammar<LLCalcParser>
namespace expression {
//TODO: If we can find a better way to do this with boost::pheonix::bind lets do it
//namespace { // anonymous
template <typename T>
T min_glue(T a, T b)
{
return std::min(a, b);
}
template <typename T>
T max_glue(T a, T b)
{
LLCalcParser(F32& result, LLCalc::calc_map_t* constants, LLCalc::calc_map_t* vars) :
mResult(result), mConstants(constants), mVariables(vars) {};
struct value_closure : closure<value_closure, F32>
return std::max(a, b);
}
struct lazy_pow_
{
template <typename X, typename Y>
struct result { typedef X type; };
template <typename X, typename Y>
X operator()(X x, Y y) const
{
member1 value;
};
template <typename ScannerT>
struct definition
return std::pow(x, y);
}
};
struct lazy_ufunc_
{
template <typename F, typename A1>
struct result { typedef A1 type; };
template <typename F, typename A1>
A1 operator()(F f, A1 a1) const
{
// Rule declarations
rule<ScannerT> statement, identifier;
rule<ScannerT, value_closure::context_t> expression, term,
power,
unary_expr,
factor,
unary_func,
binary_func,
group;
// start() should return the starting symbol
rule<ScannerT> const& start() const { return statement; }
definition(LLCalcParser const& self)
return f(a1);
}
};
struct lazy_bfunc_
{
template <typename F, typename A1, typename A2>
struct result { typedef A1 type; };
template <typename F, typename A1, typename A2>
A1 operator()(F f, A1 a1, A2 a2) const
{
return f(a1, a2);
}
};
//} // end namespace anonymous
template <typename FPT, typename Iterator>
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<Iterator>::value_type,
FPT
>
{
constant_()
{
using namespace phoenix;
assertion<std::string> assert_domain("Domain error");
// assertion<std::string> assert_symbol("Unknown symbol");
assertion<std::string> assert_syntax("Syntax error");
identifier =
lexeme_d[(alpha_p | '_') >> *(alnum_p | '_')]
;
group =
'(' >> expression[group.value = arg1] >> assert_syntax(ch_p(')'))
;
unary_func =
((str_p("SIN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sin)(self,arg1)]) |
(str_p("COS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_cos)(self,arg1)]) |
(str_p("TAN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_tan)(self,arg1)]) |
(str_p("ASIN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_asin)(self,arg1)]) |
(str_p("ACOS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_acos)(self,arg1)]) |
(str_p("ATAN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_atan)(self,arg1)]) |
(str_p("SQRT") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sqrt)(self,arg1)]) |
(str_p("LOG") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_log)(self,arg1)]) |
(str_p("EXP") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_exp)(self,arg1)]) |
(str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)]) |
(str_p("FLR") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_floor)(self,arg1)]) |
(str_p("CEIL") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_ceil)(self,arg1)])
) >> assert_syntax(ch_p(')'))
;
binary_func =
((str_p("ATAN2") >> '(' >> expression[binary_func.value = arg1] >> ',' >>
expression[binary_func.value = bind(&LLCalcParser::_atan2)(self, binary_func.value, arg1)]) |
(str_p("MIN") >> '(' >> expression[binary_func.value = arg1] >> ',' >>
expression[binary_func.value = bind(&LLCalcParser::_min)(self, binary_func.value, arg1)]) |
(str_p("MAX") >> '(' >> expression[binary_func.value = arg1] >> ',' >>
expression[binary_func.value = bind(&LLCalcParser::_max)(self, binary_func.value, arg1)])
) >> assert_syntax(ch_p(')'))
;
// *TODO: Localisation of the decimal point?
// Problem, LLLineEditor::postvalidateFloat accepts a comma when appropriate
// for the current locale. However to do that here could clash with using
// the comma as a separator when passing arguments to functions.
factor =
(ureal_p[factor.value = arg1] |
group[factor.value = arg1] |
unary_func[factor.value = arg1] |
binary_func[factor.value = arg1] |
// Lookup throws an Unknown Symbol error if it is unknown, while this works fine,
// would be "neater" to handle symbol lookup from here with an assertive parser.
// constants_p[factor.value = arg1]|
identifier[factor.value = bind(&LLCalcParser::lookup)(self, arg1, arg2)]
) >>
// Detect and throw math errors.
assert_domain(eps_p(bind(&LLCalcParser::checkNaN)(self, factor.value)))
}
} constant;
// symbol table for unary functions like "abs"
struct ufunc_
: boost::spirit::qi::symbols<
typename std::iterator_traits<Iterator>::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;
unary_expr =
!ch_p('+') >> factor[unary_expr.value = arg1] |
'-' >> factor[unary_expr.value = -arg1]
// symbol table for binary functions like "pow"
struct bfunc_
: boost::spirit::qi::symbols<
typename std::iterator_traits<Iterator>::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)
;
power =
unary_expr[power.value = arg1] >>
*('^' >> assert_syntax(unary_expr[power.value = bind(&powf)(power.value, arg1)]))
}
} 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<FPT,real_policies<FPT> > 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_> lazy_pow;
boost::phoenix::function<lazy_ufunc_> lazy_ufunc;
boost::phoenix::function<lazy_bfunc_> lazy_bfunc;
expression =
term [_val = _1]
>> *( ('+' >> term [_val += _1])
| ('-' >> term [_val -= _1])
)
;
term =
power[term.value = arg1] >>
*(('*' >> assert_syntax(power[term.value *= arg1])) |
('/' >> assert_syntax(power[term.value /= arg1])) |
('%' >> assert_syntax(power[term.value = bind(&fmodf)(term.value, arg1)]))
term =
factor [_val = _1]
>> *( ('*' >> factor [_val *= _1])
| ('/' >> factor [_val /= _1])
)
;
expression =
assert_syntax(term[expression.value = arg1]) >>
*(('+' >> assert_syntax(term[expression.value += arg1])) |
('-' >> assert_syntax(term[expression.value -= arg1]))
factor =
primary [_val = _1]
>> *( ("**" >> factor [_val = lazy_pow(_val, _1)])
)
;
statement =
!ch_p('=') >> ( expression )[var(self.mResult) = arg1] >> (end_p)
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]
;
}
};
private:
// Member functions for semantic actions
F32 lookup(const std::string::iterator&, const std::string::iterator&) const;
F32 _min(const F32& a, const F32& b) const { return llmin(a, b); }
F32 _max(const F32& a, const F32& b) const { return llmax(a, b); }
bool checkNaN(const F32& a) const { return !llisnan(a); }
//FIX* non ambiguous function fix making SIN() work for calc -Cryogenic Blitz
F32 _sin(const F32& a) const { return sin(DEG_TO_RAD * a); }
F32 _cos(const F32& a) const { return cos(DEG_TO_RAD * a); }
F32 _tan(const F32& a) const { return tan(DEG_TO_RAD * a); }
F32 _asin(const F32& a) const { return asin(a) * RAD_TO_DEG; }
F32 _acos(const F32& a) const { return acos(a) * RAD_TO_DEG; }
F32 _atan(const F32& a) const { return atan(a) * RAD_TO_DEG; }
F32 _sqrt(const F32& a) const { return sqrt(a); }
F32 _log(const F32& a) const { return log(a); }
F32 _exp(const F32& a) const { return exp(a); }
F32 _fabs(const F32& a) const { return fabs(a); }
F32 _floor(const F32& a) const { return (F32)llfloor(a); }
F32 _ceil(const F32& a) const { return llceil(a); }
F32 _atan2(const F32& a,const F32& b) const { return atan2(a,b); }
LLCalc::calc_map_t* mConstants;
LLCalc::calc_map_t* mVariables;
// LLCalc::calc_map_t* mUserVariables;
F32& mResult;
}
};
template <typename FPT, typename Iterator>
bool parse(Iterator &iter,
Iterator end,
const grammar<FPT,Iterator> &g,
FPT &result)
{
return boost::spirit::qi::phrase_parse(
iter, end, g, boost::spirit::ascii::space, result);
}
} // end namespace expression
#endif // LL_CALCPARSER_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment