From dd99e2a6b5054927bba83d44a7a03bc365c28a77 Mon Sep 17 00:00:00 2001 From: McCabe Maxsted Date: Mon, 12 Jan 2009 02:17:03 -0700 Subject: Applied Aimee's patch for doing simple math in the build editor --- linden/indra/llmath/llcalcparser.h | 155 +++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 linden/indra/llmath/llcalcparser.h (limited to 'linden/indra/llmath/llcalcparser.h') diff --git a/linden/indra/llmath/llcalcparser.h b/linden/indra/llmath/llcalcparser.h new file mode 100644 index 0000000..c405b62 --- /dev/null +++ b/linden/indra/llmath/llcalcparser.h @@ -0,0 +1,155 @@ +/* + * LLCalcParser.h + * SecondLife + * + * Created by Aimee Walton on 28/09/2008. + * Copyright 2008 Aimee Walton. + * + */ + +#ifndef LL_CALCPARSER_H +#define LL_CALCPARSER_H + +#include +#include +#include +#include +#include +//#include +#include +#include + +#include "llcalc.h" +#include "llmath.h" + +struct LLCalcParser : boost::spirit::grammar +{ + LLCalcParser(F32& result, LLCalc::calc_map_t* constants, LLCalc::calc_map_t* vars) : + mResult(result), mConstants(constants), mVariables(vars) {}; + + struct value_closure : boost::spirit::closure + { + member1 value; + }; + + template + struct definition + { + // Rule declarations + boost::spirit::rule statement, identifier; + boost::spirit::rule expression, term, + power, + unary_expr, + factor, + /*unary_func, + /binary_func,*/ + group; + + // start() should return the starting symbol + boost::spirit::rule const& start() const { return statement; } + + definition(LLCalcParser const& self) + { + using namespace boost::spirit; + using namespace phoenix; + + assertion assert_domain("Domain error"); +// assertion assert_symbol("Unknown symbol"); + assertion 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(&sin)(DEG_TO_RAD * arg1)]) | + (str_p("COS") >> '(' >> expression[unary_func.value = bind(&cos)(DEG_TO_RAD * arg1)]) | + (str_p("TAN") >> '(' >> expression[unary_func.value = bind(&tan)(DEG_TO_RAD * arg1)]) | + (str_p("ASIN") >> '(' >> expression[unary_func.value = (bind(&asin)(arg1)) * RAD_TO_DEG]) | + (str_p("ACOS") >> '(' >> expression[unary_func.value = bind(&acos)(arg1) * RAD_TO_DEG]) | + (str_p("ATAN") >> '(' >> expression[unary_func.value = bind(&atan)(arg1) * RAD_TO_DEG]) | + (str_p("SQRT") >> '(' >> expression[unary_func.value = bind(&sqrt)(arg1)]) | + (str_p("LOG") >> '(' >> expression[unary_func.value = bind(&log)(arg1)]) | + (str_p("EXP") >> '(' >> expression[unary_func.value = bind(&exp)(arg1)]) | + (str_p("ABS") >> '(' >> expression[unary_func.value = bind(&fabs)(arg1)]) + ) >> assert_syntax(ch_p(')')) + ; + + binary_func = + ((str_p("ATAN2") >> '(' >> expression[binary_func.value = arg1] >> ',' >> + expression[binary_func.value = bind(&atan2)(binary_func.value, arg1) * RAD_TO_DEG]) | + (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))) + ; + + unary_expr = + !ch_p('+') >> factor[unary_expr.value = arg1] | + '-' >> factor[unary_expr.value = -arg1] + ; + + power = + unary_expr[power.value = arg1] >> + *('^' >> assert_syntax(unary_expr[power.value = bind(&powf)(power.value, arg1)])) + ; + + term = + power[term.value = arg1] >> + *(('*' >> assert_syntax(power[term.value *= arg1])) | + ('/' >> assert_syntax(power[term.value /= arg1])) + ) + ; + + expression = + assert_syntax(term[expression.value = arg1]) >> + *(('+' >> assert_syntax(term[expression.value += arg1])) | + ('-' >> assert_syntax(term[expression.value -= arg1])) + ) + ; + + statement = + !ch_p('=') >> ( expression )[var(self.mResult) = arg1] >> (end_p) + ; + } + }; + +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); } + + LLCalc::calc_map_t* mConstants; + LLCalc::calc_map_t* mVariables; +// LLCalc::calc_map_t* mUserVariables; + + F32& mResult; +}; + +#endif // LL_CALCPARSER_H -- cgit v1.1