/src/muparser/include/muParserBase.h
Line | Count | Source |
1 | | /* |
2 | | |
3 | | _____ __ _____________ _______ ______ ___________ |
4 | | / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ |
5 | | | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |
6 | | |__|_| /____/| __(____ /__| /____ >\___ >__| |
7 | | \/ |__| \/ \/ \/ |
8 | | Copyright (C) 2004 - 2026 Ingo Berg |
9 | | |
10 | | Redistribution and use in source and binary forms, with or without modification, are permitted |
11 | | provided that the following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above copyright notice, this list of |
14 | | conditions and the following disclaimer. |
15 | | * Redistributions in binary form must reproduce the above copyright notice, this list of |
16 | | conditions and the following disclaimer in the documentation and/or other materials provided |
17 | | with the distribution. |
18 | | |
19 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR |
20 | | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
22 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
25 | | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
26 | | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | | */ |
28 | | |
29 | | #ifndef MU_PARSER_BASE_H |
30 | | #define MU_PARSER_BASE_H |
31 | | |
32 | | //--- Standard includes ------------------------------------------------------------------------ |
33 | | #include <cmath> |
34 | | #include <string> |
35 | | #include <iostream> |
36 | | #include <map> |
37 | | #include <memory> |
38 | | #include <locale> |
39 | | #include <limits.h> |
40 | | |
41 | | //--- Parser includes -------------------------------------------------------------------------- |
42 | | #include "muParserDef.h" |
43 | | #include "muParserTokenReader.h" |
44 | | #include "muParserBytecode.h" |
45 | | #include "muParserError.h" |
46 | | |
47 | | #if defined(_MSC_VER) |
48 | | #pragma warning(push) |
49 | | #pragma warning(disable : 4251) // ...needs to have dll-interface to be used by clients of class ... |
50 | | #endif |
51 | | |
52 | | |
53 | | namespace mu |
54 | | { |
55 | | namespace Test { |
56 | | class ParserTester; |
57 | | } |
58 | | |
59 | | /** \file |
60 | | \brief This file contains the class definition of the muparser engine. |
61 | | */ |
62 | | |
63 | | /** \brief Mathematical expressions parser (base parser engine). |
64 | | |
65 | | This is the implementation of a bytecode based mathematical expressions parser. |
66 | | The formula will be parsed from string and converted into a bytecode. |
67 | | Future calculations will be done with the bytecode instead the formula string |
68 | | resulting in a significant performance increase. |
69 | | Complementary to a set of internally implemented functions the parser is able to handle |
70 | | user defined functions and variables. |
71 | | */ |
72 | | class API_EXPORT_CXX ParserBase |
73 | | { |
74 | | friend class ParserTokenReader; |
75 | | friend class mu::Test::ParserTester; |
76 | | |
77 | | private: |
78 | | |
79 | | /** \brief Typedef for the parse functions. |
80 | | |
81 | | The parse function do the actual work. The parser exchanges |
82 | | the function pointer to the parser function depending on |
83 | | which state it is in. (i.e. bytecode parser vs. string parser) |
84 | | */ |
85 | | typedef value_type(ParserBase::* ParseFunction)() const; |
86 | | |
87 | | /** \brief Type used for storing an array of values. */ |
88 | | typedef std::vector<value_type> valbuf_type; |
89 | | |
90 | | /** \brief Type for a vector of strings. */ |
91 | | typedef std::vector<string_type> stringbuf_type; |
92 | | |
93 | | /** \brief Typedef for the token reader. */ |
94 | | typedef ParserTokenReader token_reader_type; |
95 | | |
96 | | /** \brief Type used for parser tokens. */ |
97 | | typedef ParserToken<value_type, string_type> token_type; |
98 | | |
99 | | /** \brief Maximum number of threads spawned by OpenMP when using the bulk mode. */ |
100 | | static const int s_MaxNumOpenMPThreads; |
101 | | |
102 | | public: |
103 | | |
104 | | /** \brief Type of the error class. |
105 | | |
106 | | Included for backwards compatibility. |
107 | | */ |
108 | | typedef ParserError exception_type; |
109 | | |
110 | | static void EnableDebugDump(bool bDumpCmd, bool bDumpStack); |
111 | | |
112 | | ParserBase(); |
113 | | ParserBase(const ParserBase& a_Parser); |
114 | | ParserBase& operator=(const ParserBase& a_Parser); |
115 | | |
116 | | virtual ~ParserBase(); |
117 | | |
118 | | value_type Eval() const; |
119 | | value_type* Eval(int& nStackSize) const; |
120 | | void Eval(value_type* results, int nBulkSize); |
121 | | |
122 | | int GetNumResults() const; |
123 | | |
124 | | void SetExpr(const string_type& a_sExpr); |
125 | | void SetVarFactory(facfun_type a_pFactory, void* pUserData = nullptr); |
126 | | |
127 | | void SetDecSep(char_type cDecSep); |
128 | | void SetThousandsSep(char_type cThousandsSep = 0); |
129 | | void ResetLocale(); |
130 | | |
131 | | void EnableOptimizer(bool a_bIsOn = true); |
132 | | void EnableBuiltInOprt(bool a_bIsOn = true); |
133 | | |
134 | | bool HasBuiltInOprt() const; |
135 | | void AddValIdent(identfun_type a_pCallback); |
136 | | |
137 | | /** \fn void mu::ParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt = true) |
138 | | \brief Define a parser function without arguments. |
139 | | \param a_strName Name of the function |
140 | | \param a_pFun Pointer to the callback function |
141 | | \param a_bAllowOpt A flag indicating this function may be optimized |
142 | | */ |
143 | | template<typename T> |
144 | | void DefineFun(const string_type& a_strName, T a_pFun, bool a_bAllowOpt = true) |
145 | 112k | { |
146 | 112k | AddCallback(a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars()); |
147 | 112k | } void mu::ParserBase::DefineFun<double (*)(double)>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, double (*)(double), bool) Line | Count | Source | 145 | 88.8k | { | 146 | 88.8k | AddCallback(a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars()); | 147 | 88.8k | } |
void mu::ParserBase::DefineFun<double (*)(double, double)>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, double (*)(double, double), bool) Line | Count | Source | 145 | 3.86k | { | 146 | 3.86k | AddCallback(a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars()); | 147 | 3.86k | } |
void mu::ParserBase::DefineFun<double (*)(double const*, int)>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, double (*)(double const*, int), bool) Line | Count | Source | 145 | 15.4k | { | 146 | 15.4k | AddCallback(a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars()); | 147 | 15.4k | } |
void mu::ParserBase::DefineFun<double (*)()>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, double (*)(), bool) Line | Count | Source | 145 | 3.86k | { | 146 | 3.86k | AddCallback(a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars()); | 147 | 3.86k | } |
|
148 | | |
149 | | /** \fn void mu::ParserBase::DefineFunUserData |
150 | | \brief Define a parser function with user data (not null). |
151 | | \param a_strName Name of the function |
152 | | \param a_pFun Pointer to the callback function |
153 | | \param a_pUserData Pointer that will be passed back to callback (shall not be nullptr) |
154 | | \param a_bAllowOpt A flag indicating this function may be optimized |
155 | | */ |
156 | | template<typename T> |
157 | | void DefineFunUserData(const string_type& a_strName, T a_pFun, void* a_pUserData, bool a_bAllowOpt = true) |
158 | | { |
159 | | AddCallback(a_strName, ParserCallback(a_pFun, a_pUserData, a_bAllowOpt), m_FunDef, ValidNameChars()); |
160 | | } |
161 | | |
162 | | /** \brief Checks the existence of a function by name. |
163 | | |
164 | | This method determines whether a function with the specified name |
165 | | is defined in the parser's function registry. |
166 | | |
167 | | \param a_strName The name of the function to check. |
168 | | \return True if the function exists, otherwise false. |
169 | | */ |
170 | | bool HasFun(const string_type& a_strName) const; |
171 | | |
172 | | void DefineOprt(const string_type& a_strName, fun_type2 a_pFun, unsigned a_iPri = 0, EOprtAssociativity a_eAssociativity = oaLEFT, bool a_bAllowOpt = false); |
173 | | void DefineConst(const string_type& a_sName, value_type a_fVal); |
174 | | void DefineStrConst(const string_type& a_sName, const string_type& a_strVal); |
175 | | void DefineVar(const string_type& a_sName, value_type* a_fVar); |
176 | | void DefinePostfixOprt(const string_type& a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt = true); |
177 | | void DefineInfixOprt(const string_type& a_strName, fun_type1 a_pOprt, int a_iPrec = prINFIX, bool a_bAllowOpt = true); |
178 | | |
179 | | // Clear user defined variables, constants or functions |
180 | | void ClearVar(); |
181 | | void ClearFun(); |
182 | | void ClearConst(); |
183 | | void ClearInfixOprt(); |
184 | | void ClearPostfixOprt(); |
185 | | void ClearOprt(); |
186 | | |
187 | | void RemoveVar(const string_type& a_strVarName); |
188 | | const varmap_type& GetUsedVar() const; |
189 | | const varmap_type& GetVar() const; |
190 | | const valmap_type& GetConst() const; |
191 | | const string_type& GetExpr() const; |
192 | | const funmap_type& GetFunDef() const; |
193 | | string_type GetVersion(EParserVersionInfo eInfo = pviFULL) const; |
194 | | const ParserByteCode& GetByteCode() const; |
195 | | |
196 | | const char_type** GetOprtDef() const; |
197 | | void DefineNameChars(const char_type* a_szCharset); |
198 | | void DefineOprtChars(const char_type* a_szCharset); |
199 | | void DefineInfixOprtChars(const char_type* a_szCharset); |
200 | | |
201 | | const char_type* ValidNameChars() const; |
202 | | const char_type* ValidOprtChars() const; |
203 | | const char_type* ValidInfixOprtChars() const; |
204 | | |
205 | | void SetArgSep(char_type cArgSep); |
206 | | void SetByteCode(const ParserByteCode& a_ByteCode); |
207 | | |
208 | | char_type GetArgSep() const; |
209 | | |
210 | | protected: |
211 | | |
212 | | void Init(); |
213 | | void Error(EErrorCodes a_iErrc, int a_iPos = static_cast<int>(mu::string_type::npos), const string_type& a_strTok = string_type()) const; |
214 | | |
215 | | virtual void InitCharSets() = 0; |
216 | | virtual void InitFun() = 0; |
217 | | virtual void InitConst() = 0; |
218 | | virtual void InitOprt() = 0; |
219 | | |
220 | | virtual void OnDetectVar(string_type* pExpr, int& nStart, int& nEnd); |
221 | | |
222 | | static const char_type* c_DefaultOprt[]; |
223 | | static std::locale s_locale; ///< The locale used by the parser |
224 | | static bool g_DbgDumpCmdCode; |
225 | | static bool g_DbgDumpStack; |
226 | | |
227 | | /** \brief A facet class used to change decimal and thousands separator. */ |
228 | | template<class TChar> |
229 | | class change_dec_sep : public std::numpunct<TChar> |
230 | | { |
231 | | public: |
232 | | |
233 | | explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) |
234 | 2 | :std::numpunct<TChar>() |
235 | 2 | ,m_nGroup(nGroup) |
236 | 2 | ,m_cDecPoint(cDecSep) |
237 | 2 | ,m_cThousandsSep(cThousandsSep) |
238 | 2 | {} |
239 | | |
240 | | protected: |
241 | | |
242 | | char_type do_decimal_point() const override |
243 | 568k | { |
244 | 568k | return m_cDecPoint; |
245 | 568k | } |
246 | | |
247 | | char_type do_thousands_sep() const override |
248 | 564k | { |
249 | 564k | return m_cThousandsSep; |
250 | 564k | } |
251 | | |
252 | | std::string do_grouping() const override |
253 | 564k | { |
254 | | // fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4 |
255 | | // courtesy of Jens Bartsch |
256 | | // original code: |
257 | | // return std::string(1, (char)m_nGroup); |
258 | | // new code: |
259 | 564k | return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX)); |
260 | 564k | } |
261 | | |
262 | | private: |
263 | | |
264 | | int m_nGroup; |
265 | | char_type m_cDecPoint; |
266 | | char_type m_cThousandsSep; |
267 | | }; |
268 | | |
269 | | private: |
270 | | |
271 | | void Assign(const ParserBase& a_Parser); |
272 | | void InitTokenReader(); |
273 | | void ReInit() const; |
274 | | |
275 | | void AddCallback(const string_type& a_strName, const ParserCallback& a_Callback, funmap_type& a_Storage, const char_type* a_szCharSet); |
276 | | void ApplyRemainingOprt(std::stack<token_type>& a_stOpt, std::stack<token_type>& a_stVal) const; |
277 | | void ApplyBinOprt(std::stack<token_type>& a_stOpt, std::stack<token_type>& a_stVal) const; |
278 | | void ApplyIfElse(std::stack<token_type>& a_stOpt, std::stack<token_type>& a_stVal) const; |
279 | | void ApplyFunc(std::stack<token_type>& a_stOpt, std::stack<token_type>& a_stVal, int iArgCount) const; |
280 | | |
281 | | token_type ApplyStrFunc(const token_type& a_FunTok, const std::vector<token_type>& a_vArg) const; |
282 | | |
283 | | int GetOprtPrecedence(const token_type& a_Tok) const; |
284 | | EOprtAssociativity GetOprtAssociativity(const token_type& a_Tok) const; |
285 | | |
286 | | void CreateRPN() const; |
287 | | |
288 | | value_type ParseString() const; |
289 | | value_type ParseCmdCode() const; |
290 | | value_type ParseCmdCodeShort() const; |
291 | | value_type ParseCmdCodeBulk(int nOffset, int nThreadID) const; |
292 | | |
293 | | void CheckName(const string_type& a_strName, const string_type& a_CharSet) const; |
294 | | void CheckOprt(const string_type& a_sName, const ParserCallback& a_Callback, const string_type& a_szCharSet) const; |
295 | | |
296 | | void StackDump(const std::stack<token_type >& a_stVal, const std::stack<token_type >& a_stOprt) const; |
297 | | |
298 | | /** \brief Pointer to the parser function. |
299 | | |
300 | | Eval() calls the function whose address is stored there. |
301 | | */ |
302 | | mutable ParseFunction m_pParseFormula; |
303 | | mutable ParserByteCode m_vRPN; ///< The Bytecode class. |
304 | | mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments |
305 | | stringbuf_type m_vStringVarBuf; |
306 | | |
307 | | std::unique_ptr<token_reader_type> m_pTokenReader; ///< Managed pointer to the token reader object. |
308 | | |
309 | | funmap_type m_FunDef; ///< Map of function names and pointers. |
310 | | funmap_type m_PostOprtDef; ///< Postfix operator callbacks |
311 | | funmap_type m_InfixOprtDef; ///< unary infix operator. |
312 | | funmap_type m_OprtDef; ///< Binary operator callbacks |
313 | | valmap_type m_ConstDef; ///< user constants. |
314 | | strmap_type m_StrVarDef; ///< user defined string constants |
315 | | varmap_type m_VarDef; ///< user defind variables. |
316 | | |
317 | | bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off |
318 | | |
319 | | string_type m_sNameChars; ///< Charset for names |
320 | | string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens |
321 | | string_type m_sInfixOprtChars; ///< Charset for infix operator tokens |
322 | | |
323 | | // items merely used for caching state information |
324 | | mutable valbuf_type m_vStackBuffer; ///< This is merely a buffer used for the stack in the cmd parsing routine |
325 | | mutable int m_nFinalResultIdx; |
326 | | }; |
327 | | |
328 | | } // namespace mu |
329 | | |
330 | | #if defined(_MSC_VER) |
331 | | #pragma warning(pop) |
332 | | #endif |
333 | | |
334 | | #endif |