PageRenderTime 38ms CodeModel.GetById 18ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmath/llcalcparser.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 191 lines | 124 code | 28 blank | 39 comment | 0 complexity | 453a9d4daa3f39f20e3b74b27ab2cea9 MD5 | raw file
  1/*
  2 *  LLCalcParser.h
  3 *  Copyright 2008 Aimee Walton.
  4 * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  5 * Second Life Viewer Source Code
  6 * Copyright (C) 2008, Linden Research, Inc.
  7 * 
  8 * This library is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU Lesser General Public
 10 * License as published by the Free Software Foundation;
 11 * version 2.1 of the License only.
 12 * 
 13 * This library is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 16 * Lesser General Public License for more details.
 17 * 
 18 * You should have received a copy of the GNU Lesser General Public
 19 * License along with this library; if not, write to the Free Software
 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 21 * 
 22 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 23 * $/LicenseInfo$
 24 *
 25 */
 26
 27#ifndef LL_CALCPARSER_H
 28#define LL_CALCPARSER_H
 29
 30#include <boost/spirit/include/classic_attribute.hpp>
 31#include <boost/spirit/include/classic_core.hpp>
 32#include <boost/spirit/include/classic_error_handling.hpp>
 33#include <boost/spirit/include/classic_position_iterator.hpp>
 34#include <boost/spirit/include/phoenix1_binders.hpp>
 35#include <boost/spirit/include/classic_symbols.hpp>
 36using namespace boost::spirit::classic;
 37
 38#include "llcalc.h"
 39#include "llmath.h"
 40
 41struct LLCalcParser : grammar<LLCalcParser>
 42{
 43	LLCalcParser(F32& result, LLCalc::calc_map_t* constants, LLCalc::calc_map_t* vars) :
 44		mResult(result), mConstants(constants), mVariables(vars) {};
 45	
 46	struct value_closure : closure<value_closure, F32>
 47	{
 48		member1 value;
 49	};
 50	
 51	template <typename ScannerT>
 52	struct definition
 53	{
 54		// Rule declarations
 55		rule<ScannerT> statement, identifier;
 56		rule<ScannerT, value_closure::context_t> expression, term,
 57			power, 
 58			unary_expr, 
 59			factor, 
 60			unary_func, 
 61			binary_func,
 62			group;
 63
 64		// start() should return the starting symbol
 65		rule<ScannerT> const& start() const { return statement; }
 66		
 67		definition(LLCalcParser const& self)
 68		{
 69			using namespace phoenix;
 70			
 71			assertion<std::string> assert_domain("Domain error");
 72//			assertion<std::string> assert_symbol("Unknown symbol");
 73			assertion<std::string> assert_syntax("Syntax error");
 74			
 75			identifier =
 76				lexeme_d[(alpha_p | '_') >> *(alnum_p | '_')]
 77			;
 78			
 79			group =
 80				'(' >> expression[group.value = arg1] >> assert_syntax(ch_p(')'))
 81			;
 82
 83			unary_func =
 84				((str_p("SIN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sin)(self,arg1)]) |
 85				 (str_p("COS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_cos)(self,arg1)]) |
 86				 (str_p("TAN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_tan)(self,arg1)]) |
 87				 (str_p("ASIN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_asin)(self,arg1)]) |
 88				 (str_p("ACOS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_acos)(self,arg1)]) |
 89				 (str_p("ATAN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_atan)(self,arg1)]) |
 90				 (str_p("SQRT") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sqrt)(self,arg1)]) |
 91				 (str_p("LOG") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_log)(self,arg1)]) |
 92				 (str_p("EXP") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_exp)(self,arg1)]) |
 93				 (str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)]) |
 94				 (str_p("FLR") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_floor)(self,arg1)]) |
 95				 (str_p("CEIL") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_ceil)(self,arg1)])
 96				) >> assert_syntax(ch_p(')'))
 97			;
 98			
 99			binary_func =
100				((str_p("ATAN2") >> '(' >> expression[binary_func.value = arg1] >> ',' >>
101				  expression[binary_func.value = bind(&LLCalcParser::_atan2)(self, binary_func.value, arg1)]) |
102				 (str_p("MIN") >> '(' >> expression[binary_func.value = arg1] >> ',' >> 
103				  expression[binary_func.value = bind(&LLCalcParser::_min)(self, binary_func.value, arg1)]) |
104				 (str_p("MAX") >> '(' >> expression[binary_func.value = arg1] >> ',' >> 
105				  expression[binary_func.value = bind(&LLCalcParser::_max)(self, binary_func.value, arg1)])
106				) >> assert_syntax(ch_p(')'))
107			;
108			
109			// *TODO: Localisation of the decimal point?
110			// Problem, LLLineEditor::postvalidateFloat accepts a comma when appropriate
111			// for the current locale. However to do that here could clash with using
112			// the comma as a separator when passing arguments to functions.
113			factor =
114				(ureal_p[factor.value = arg1] |
115				 group[factor.value = arg1] |
116				 unary_func[factor.value = arg1] |
117				 binary_func[factor.value = arg1] |
118				 // Lookup throws an Unknown Symbol error if it is unknown, while this works fine,
119				 // would be "neater" to handle symbol lookup from here with an assertive parser.
120//				 constants_p[factor.value = arg1]|
121				 identifier[factor.value = bind(&LLCalcParser::lookup)(self, arg1, arg2)]
122				) >>
123				// Detect and throw math errors.
124				assert_domain(eps_p(bind(&LLCalcParser::checkNaN)(self, factor.value)))
125			;
126
127			unary_expr =
128				!ch_p('+') >> factor[unary_expr.value = arg1] |
129				'-' >> factor[unary_expr.value = -arg1]
130			;
131			
132			power =
133				unary_expr[power.value = arg1] >>
134				*('^' >> assert_syntax(unary_expr[power.value = bind(&powf)(power.value, arg1)]))
135			;
136			
137			term =
138				power[term.value = arg1] >>
139				*(('*' >> assert_syntax(power[term.value *= arg1])) |
140				  ('/' >> assert_syntax(power[term.value /= arg1])) |
141				  ('%' >> assert_syntax(power[term.value = bind(&fmodf)(term.value, arg1)]))
142				)
143			;
144			
145			expression =
146				assert_syntax(term[expression.value = arg1]) >>
147				*(('+' >> assert_syntax(term[expression.value += arg1])) |
148				  ('-' >> assert_syntax(term[expression.value -= arg1]))
149				)
150			;
151
152			statement =
153				!ch_p('=') >> ( expression )[var(self.mResult) = arg1] >> (end_p)
154			;
155		}
156	};
157	
158private:
159	// Member functions for semantic actions
160	F32	lookup(const std::string::iterator&, const std::string::iterator&) const;
161	F32 _min(const F32& a, const F32& b) const { return llmin(a, b); }
162	F32 _max(const F32& a, const F32& b) const { return llmax(a, b); }
163	
164	bool checkNaN(const F32& a) const { return !llisnan(a); }
165	
166	//FIX* non ambigious function fix making SIN() work for calc -Cryogenic Blitz
167	F32 _sin(const F32& a) const { return sin(DEG_TO_RAD * a); }
168	F32 _cos(const F32& a) const { return cos(DEG_TO_RAD * a); }
169	F32 _tan(const F32& a) const { return tan(DEG_TO_RAD * a); }
170	F32 _asin(const F32& a) const { return asin(a * RAD_TO_DEG); }
171	F32 _acos(const F32& a) const { return acos(a * RAD_TO_DEG); }
172	F32 _atan(const F32& a) const { return atan(a * RAD_TO_DEG); }
173	F32 _sqrt(const F32& a) const { return sqrt(a); }
174	F32 _log(const F32& a) const { return log(a); }
175	F32 _exp(const F32& a) const { return exp(a); }
176	F32 _fabs(const F32& a) const { return fabs(a); }
177	F32 _floor(const F32& a) const { return llfloor(a); }
178	F32 _ceil(const F32& a) const { return llceil(a); }
179
180	F32 _atan2(const F32& a,const F32& b) const { return atan2(a,b); }
181
182
183
184	LLCalc::calc_map_t* mConstants;
185	LLCalc::calc_map_t* mVariables;
186//	LLCalc::calc_map_t* mUserVariables;
187	
188	F32&		mResult;
189};
190
191#endif // LL_CALCPARSER_H