1 /*
2 
3 	 _____  __ _____________ _______  ______ ___________
4 	/     \|  |  \____ \__  \\_  __ \/  ___// __ \_  __ \
5    |  Y Y  \  |  /  |_> > __ \|  | \/\___ \\  ___/|  | \/
6    |__|_|  /____/|   __(____  /__|  /____  >\___  >__|
7 		 \/      |__|       \/           \/     \/
8    Copyright (C) 2004 - 2020 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 #include "muParserBase.h"
30 #include "muParserTemplateMagic.h"
31 
32 //--- Standard includes ------------------------------------------------------------------------
33 #include <algorithm>
34 #include <cmath>
35 #include <memory>
36 #include <vector>
37 #include <deque>
38 #include <sstream>
39 #include <locale>
40 #include <cassert>
41 #include <cctype>
42 
43 #ifdef MUP_USE_OPENMP
44 #include <omp.h>
45 #endif
46 
47 #if defined(_MSC_VER)
48 	#pragma warning(push)
49 	#pragma warning(disable : 26812)
50 #endif
51 
52 using namespace std;
53 
54 /** \file
55 	\brief This file contains the basic implementation of the muparser engine.
56 */
57 
58 namespace mu
59 {
60 	std::locale ParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep<char_type>('.'));
61 
62 	bool ParserBase::g_DbgDumpCmdCode = false;
63 	bool ParserBase::g_DbgDumpStack = false;
64 
65 	//------------------------------------------------------------------------------
66 	/** \brief Identifiers for built in binary operators.
67 
68 		When defining custom binary operators with #AddOprt(...) make sure not to choose
69 		names conflicting with these definitions.
70 	*/
71 	const char_type* ParserBase::c_DefaultOprt[] =
72 	{
73 	  _T("<="), _T(">="),  _T("!="),
74 	  _T("=="), _T("<"),   _T(">"),
75 	  _T("+"),  _T("-"),   _T("*"),
76 	  _T("/"),  _T("^"),   _T("&&"),
77 	  _T("||"), _T("="),   _T("("),
78 	  _T(")"),   _T("?"),  _T(":"), 0
79 	};
80 
81 	const int ParserBase::s_MaxNumOpenMPThreads = 16;
82 
83 	//------------------------------------------------------------------------------
84 	/** \brief Constructor.
85 		\param a_szFormula the formula to interpret.
86 		\throw ParserException if a_szFormula is nullptr.
87 	*/
ParserBase()88 	ParserBase::ParserBase()
89 		: m_pParseFormula(&ParserBase::ParseString)
90 		, m_vRPN()
91 		, m_vStringBuf()
92 		, m_pTokenReader()
93 		, m_FunDef()
94 		, m_PostOprtDef()
95 		, m_InfixOprtDef()
96 		, m_OprtDef()
97 		, m_ConstDef()
98 		, m_StrVarDef()
99 		, m_VarDef()
100 		, m_bBuiltInOp(true)
101 		, m_sNameChars()
102 		, m_sOprtChars()
103 		, m_sInfixOprtChars()
104 		, m_vStackBuffer()
105 		, m_nFinalResultIdx(0)
106 	{
107 		InitTokenReader();
108 	}
109 
110 	//---------------------------------------------------------------------------
111 	/** \brief Copy constructor.
112 
113 	  The parser can be safely copy constructed but the bytecode is reset during
114 	  copy construction.
115 	*/
ParserBase(const ParserBase & a_Parser)116 	ParserBase::ParserBase(const ParserBase& a_Parser)
117 		: m_pParseFormula(&ParserBase::ParseString)
118 		, m_vRPN()
119 		, m_vStringBuf()
120 		, m_pTokenReader()
121 		, m_FunDef()
122 		, m_PostOprtDef()
123 		, m_InfixOprtDef()
124 		, m_OprtDef()
125 		, m_ConstDef()
126 		, m_StrVarDef()
127 		, m_VarDef()
128 		, m_bBuiltInOp(true)
129 		, m_sNameChars()
130 		, m_sOprtChars()
131 		, m_sInfixOprtChars()
132 	{
133 		m_pTokenReader.reset(new token_reader_type(this));
134 		Assign(a_Parser);
135 	}
136 
137 	//---------------------------------------------------------------------------
~ParserBase()138 	ParserBase::~ParserBase()
139 	{}
140 
141 	//---------------------------------------------------------------------------
142 	/** \brief Assignment operator.
143 
144 	  Implemented by calling Assign(a_Parser). Self assignment is suppressed.
145 	  \param a_Parser Object to copy to this.
146 	  \return *this
147 	  \throw nothrow
148 	*/
operator =(const ParserBase & a_Parser)149 	ParserBase& ParserBase::operator=(const ParserBase& a_Parser)
150 	{
151 		Assign(a_Parser);
152 		return *this;
153 	}
154 
155 	//---------------------------------------------------------------------------
156 	/** \brief Copy state of a parser object to this.
157 
158 	  Clears Variables and Functions of this parser.
159 	  Copies the states of all internal variables.
160 	  Resets parse function to string parse mode.
161 
162 	  \param a_Parser the source object.
163 	*/
Assign(const ParserBase & a_Parser)164 	void ParserBase::Assign(const ParserBase& a_Parser)
165 	{
166 		if (&a_Parser == this)
167 			return;
168 
169 		// Don't copy bytecode instead cause the parser to create new bytecode
170 		// by resetting the parse function.
171 		ReInit();
172 
173 		m_ConstDef = a_Parser.m_ConstDef;         // Copy user define constants
174 		m_VarDef = a_Parser.m_VarDef;           // Copy user defined variables
175 		m_bBuiltInOp = a_Parser.m_bBuiltInOp;
176 		m_vStringBuf = a_Parser.m_vStringBuf;
177 		m_vStackBuffer = a_Parser.m_vStackBuffer;
178 		m_nFinalResultIdx = a_Parser.m_nFinalResultIdx;
179 		m_StrVarDef = a_Parser.m_StrVarDef;
180 		m_vStringVarBuf = a_Parser.m_vStringVarBuf;
181 		m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this));
182 
183 		// Copy function and operator callbacks
184 		m_FunDef = a_Parser.m_FunDef;             // Copy function definitions
185 		m_PostOprtDef = a_Parser.m_PostOprtDef;   // post value unary operators
186 		m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation
187 		m_OprtDef = a_Parser.m_OprtDef;           // binary operators
188 
189 		m_sNameChars = a_Parser.m_sNameChars;
190 		m_sOprtChars = a_Parser.m_sOprtChars;
191 		m_sInfixOprtChars = a_Parser.m_sInfixOprtChars;
192 	}
193 
194 	//---------------------------------------------------------------------------
195 	/** \brief Set the decimal separator.
196 		\param cDecSep Decimal separator as a character value.
197 		\sa SetThousandsSep
198 
199 		By default muparser uses the "C" locale. The decimal separator of this
200 		locale is overwritten by the one provided here.
201 	*/
SetDecSep(char_type cDecSep)202 	void ParserBase::SetDecSep(char_type cDecSep)
203 	{
204 		char_type cThousandsSep = std::use_facet< change_dec_sep<char_type> >(s_locale).thousands_sep();
205 		s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>(cDecSep, cThousandsSep));
206 	}
207 
208 	//---------------------------------------------------------------------------
209 	/** \brief Sets the thousands operator.
210 		\param cThousandsSep The thousands separator as a character
211 		\sa SetDecSep
212 
213 		By default muparser uses the "C" locale. The thousands separator of this
214 		locale is overwritten by the one provided here.
215 	*/
SetThousandsSep(char_type cThousandsSep)216 	void ParserBase::SetThousandsSep(char_type cThousandsSep)
217 	{
218 		char_type cDecSep = std::use_facet< change_dec_sep<char_type> >(s_locale).decimal_point();
219 		s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>(cDecSep, cThousandsSep));
220 	}
221 
222 	//---------------------------------------------------------------------------
223 	/** \brief Resets the locale.
224 
225 	  The default locale used "." as decimal separator, no thousands separator and
226 	  "," as function argument separator.
227 	*/
ResetLocale()228 	void ParserBase::ResetLocale()
229 	{
230 		s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>('.'));
231 		SetArgSep(',');
232 	}
233 
234 	//---------------------------------------------------------------------------
235 	/** \brief Initialize the token reader.
236 
237 	  Create new token reader object and submit pointers to function, operator,
238 	  constant and variable definitions.
239 
240 	  \post m_pTokenReader.get()!=0
241 	  \throw nothrow
242 	*/
InitTokenReader()243 	void ParserBase::InitTokenReader()
244 	{
245 		m_pTokenReader.reset(new token_reader_type(this));
246 	}
247 
248 	//---------------------------------------------------------------------------
249 	/** \brief Reset parser to string parsing mode and clear internal buffers.
250 
251 		Clear bytecode, reset the token reader.
252 		\throw nothrow
253 	*/
ReInit() const254 	void ParserBase::ReInit() const
255 	{
256 		m_pParseFormula = &ParserBase::ParseString;
257 		m_vStringBuf.clear();
258 		m_vRPN.clear();
259 		m_pTokenReader->ReInit();
260 	}
261 
262 	//---------------------------------------------------------------------------
OnDetectVar(string_type *,int &,int &)263 	void ParserBase::OnDetectVar(string_type* /*pExpr*/, int& /*nStart*/, int& /*nEnd*/)
264 	{}
265 
266 	//---------------------------------------------------------------------------
267 	/** \brief Returns the version of muparser.
268 		\param eInfo A flag indicating whether the full version info should be
269 					 returned or not.
270 
271 	  Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS
272 	  are returned only if eInfo==pviFULL.
273 	*/
GetVersion(EParserVersionInfo eInfo) const274 	string_type ParserBase::GetVersion(EParserVersionInfo eInfo) const
275 	{
276 		stringstream_type ss;
277 
278 		ss << ParserVersion;
279 
280 		if (eInfo == pviFULL)
281 		{
282 			ss << _T(" (") << ParserVersionDate;
283 			ss << std::dec << _T("; ") << sizeof(void*) * 8 << _T("BIT");
284 
285 #ifdef _DEBUG
286 			ss << _T("; DEBUG");
287 #else
288 			ss << _T("; RELEASE");
289 #endif
290 
291 #ifdef _UNICODE
292 			ss << _T("; UNICODE");
293 #else
294 #ifdef _MBCS
295 			ss << _T("; MBCS");
296 #else
297 			ss << _T("; ASCII");
298 #endif
299 #endif
300 
301 #ifdef MUP_USE_OPENMP
302 			ss << _T("; OPENMP");
303 #endif
304 
305 			ss << _T(")");
306 		}
307 
308 		return ss.str();
309 	}
310 
311 	//---------------------------------------------------------------------------
312 	/** \brief Add a value parsing function.
313 
314 		When parsing an expression muParser tries to detect values in the expression
315 		string using different valident callbacks. Thus it's possible to parse
316 		for hex values, binary values and floating point values.
317 	*/
AddValIdent(identfun_type a_pCallback)318 	void ParserBase::AddValIdent(identfun_type a_pCallback)
319 	{
320 		m_pTokenReader->AddValIdent(a_pCallback);
321 	}
322 
323 	//---------------------------------------------------------------------------
324 	/** \brief Set a function that can create variable pointer for unknown expression variables.
325 		\param a_pFactory A pointer to the variable factory.
326 		\param pUserData A user defined context pointer.
327 	*/
SetVarFactory(facfun_type a_pFactory,void * pUserData)328 	void ParserBase::SetVarFactory(facfun_type a_pFactory, void* pUserData)
329 	{
330 		m_pTokenReader->SetVarCreator(a_pFactory, pUserData);
331 	}
332 
333 	//---------------------------------------------------------------------------
334 	/** \brief Add a function or operator callback to the parser. */
AddCallback(const string_type & a_strName,const ParserCallback & a_Callback,funmap_type & a_Storage,const char_type * a_szCharSet)335 	void ParserBase::AddCallback(const string_type& a_strName,
336 		const ParserCallback& a_Callback,
337 		funmap_type& a_Storage,
338 		const char_type* a_szCharSet)
339 	{
340 		if (a_Callback.GetAddr() == 0)
341 			Error(ecINVALID_FUN_PTR);
342 
343 		const funmap_type* pFunMap = &a_Storage;
344 
345 		// Check for conflicting operator or function names
346 		if (pFunMap != &m_FunDef && m_FunDef.find(a_strName) != m_FunDef.end())
347 			Error(ecNAME_CONFLICT, -1, a_strName);
348 
349 		if (pFunMap != &m_PostOprtDef && m_PostOprtDef.find(a_strName) != m_PostOprtDef.end())
350 			Error(ecNAME_CONFLICT, -1, a_strName);
351 
352 		if (pFunMap != &m_InfixOprtDef && pFunMap != &m_OprtDef && m_InfixOprtDef.find(a_strName) != m_InfixOprtDef.end())
353 			Error(ecNAME_CONFLICT, -1, a_strName);
354 
355 		if (pFunMap != &m_InfixOprtDef && pFunMap != &m_OprtDef && m_OprtDef.find(a_strName) != m_OprtDef.end())
356 			Error(ecNAME_CONFLICT, -1, a_strName);
357 
358 		CheckOprt(a_strName, a_Callback, a_szCharSet);
359 		a_Storage[a_strName] = a_Callback;
360 		ReInit();
361 	}
362 
363 	//---------------------------------------------------------------------------
364 	/** \brief Check if a name contains invalid characters.
365 
366 		\throw ParserException if the name contains invalid characters.
367 	*/
CheckOprt(const string_type & a_sName,const ParserCallback & a_Callback,const string_type & a_szCharSet) const368 	void ParserBase::CheckOprt(const string_type& a_sName,
369 		const ParserCallback& a_Callback,
370 		const string_type& a_szCharSet) const
371 	{
372 		if (!a_sName.length() ||
373 			(a_sName.find_first_not_of(a_szCharSet) != string_type::npos) ||
374 			(a_sName[0] >= '0' && a_sName[0] <= '9'))
375 		{
376 			switch (a_Callback.GetCode())
377 			{
378 			case cmOPRT_POSTFIX: Error(ecINVALID_POSTFIX_IDENT, -1, a_sName); break;
379 			case cmOPRT_INFIX:   Error(ecINVALID_INFIX_IDENT, -1, a_sName); break;
380 			default:             Error(ecINVALID_NAME, -1, a_sName);
381 			}
382 		}
383 	}
384 
385 	//---------------------------------------------------------------------------
386 	/** \brief Check if a name contains invalid characters.
387 
388 		\throw ParserException if the name contains invalid characters.
389 	*/
CheckName(const string_type & a_sName,const string_type & a_szCharSet) const390 	void ParserBase::CheckName(const string_type& a_sName,
391 		const string_type& a_szCharSet) const
392 	{
393 		if (!a_sName.length() ||
394 			(a_sName.find_first_not_of(a_szCharSet) != string_type::npos) ||
395 			(a_sName[0] >= '0' && a_sName[0] <= '9'))
396 		{
397 			Error(ecINVALID_NAME);
398 		}
399 	}
400 
401 	//---------------------------------------------------------------------------
402 	/** \brief Set the formula.
403 		\param a_strFormula Formula as string_type
404 		\throw ParserException in case of syntax errors.
405 
406 		Triggers first time calculation thus the creation of the bytecode and
407 		scanning of used variables.
408 	*/
SetExpr(const string_type & a_sExpr)409 	void ParserBase::SetExpr(const string_type& a_sExpr)
410 	{
411 		if (std::all_of(a_sExpr.begin(), a_sExpr.end(), [](char c) { return !std::isgraph(c); }))
412 		{
413 			Error(ecINVALID_CHARACTERS_FOUND);
414 		}
415 
416 		// Check locale compatibility
417 		if (m_pTokenReader->GetArgSep() == std::use_facet<numpunct<char_type> >(s_locale).decimal_point())
418 			Error(ecLOCALE);
419 
420 		// Check maximum allowed expression length. An arbitrary value small enough so i can debug expressions sent to me
421 		if (a_sExpr.length() >= MaxLenExpression)
422 			Error(ecEXPRESSION_TOO_LONG, 0, a_sExpr);
423 
424 		m_pTokenReader->SetFormula(a_sExpr + _T(" "));
425 		ReInit();
426 	}
427 
428 	//---------------------------------------------------------------------------
429 	/** \brief Get the default symbols used for the built in operators.
430 		\sa c_DefaultOprt
431 	*/
GetOprtDef() const432 	const char_type** ParserBase::GetOprtDef() const
433 	{
434 		return (const char_type**)(&c_DefaultOprt[0]);
435 	}
436 
437 	//---------------------------------------------------------------------------
438 	/** \brief Define the set of valid characters to be used in names of
439 			   functions, variables, constants.
440 	*/
DefineNameChars(const char_type * a_szCharset)441 	void ParserBase::DefineNameChars(const char_type* a_szCharset)
442 	{
443 		m_sNameChars = a_szCharset;
444 	}
445 
446 	//---------------------------------------------------------------------------
447 	/** \brief Define the set of valid characters to be used in names of
448 			   binary operators and postfix operators.
449 	*/
DefineOprtChars(const char_type * a_szCharset)450 	void ParserBase::DefineOprtChars(const char_type* a_szCharset)
451 	{
452 		m_sOprtChars = a_szCharset;
453 	}
454 
455 	//---------------------------------------------------------------------------
456 	/** \brief Define the set of valid characters to be used in names of
457 			   infix operators.
458 	*/
DefineInfixOprtChars(const char_type * a_szCharset)459 	void ParserBase::DefineInfixOprtChars(const char_type* a_szCharset)
460 	{
461 		m_sInfixOprtChars = a_szCharset;
462 	}
463 
464 	//---------------------------------------------------------------------------
465 	/** \brief Virtual function that defines the characters allowed in name identifiers.
466 		\sa #ValidOprtChars, #ValidPrefixOprtChars
467 	*/
ValidNameChars() const468 	const char_type* ParserBase::ValidNameChars() const
469 	{
470 		MUP_ASSERT(m_sNameChars.size());
471 		return m_sNameChars.c_str();
472 	}
473 
474 	//---------------------------------------------------------------------------
475 	/** \brief Virtual function that defines the characters allowed in operator definitions.
476 		\sa #ValidNameChars, #ValidPrefixOprtChars
477 	*/
ValidOprtChars() const478 	const char_type* ParserBase::ValidOprtChars() const
479 	{
480 		MUP_ASSERT(m_sOprtChars.size());
481 		return m_sOprtChars.c_str();
482 	}
483 
484 	//---------------------------------------------------------------------------
485 	/** \brief Virtual function that defines the characters allowed in infix operator definitions.
486 		\sa #ValidNameChars, #ValidOprtChars
487 	*/
ValidInfixOprtChars() const488 	const char_type* ParserBase::ValidInfixOprtChars() const
489 	{
490 		MUP_ASSERT(m_sInfixOprtChars.size());
491 		return m_sInfixOprtChars.c_str();
492 	}
493 
494 	//---------------------------------------------------------------------------
495 	/** \brief Add a user defined operator.
496 		\post Will reset the Parser to string parsing mode.
497 	*/
DefinePostfixOprt(const string_type & a_sName,fun_type1 a_pFun,bool a_bAllowOpt)498 	void ParserBase::DefinePostfixOprt(const string_type& a_sName, fun_type1 a_pFun, bool a_bAllowOpt)
499 	{
500 		if (a_sName.length() > MaxLenIdentifier)
501 			Error(ecIDENTIFIER_TOO_LONG);
502 
503 		AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), m_PostOprtDef, ValidOprtChars());
504 	}
505 
506 	//---------------------------------------------------------------------------
507 	/** \brief Initialize user defined functions.
508 
509 	  Calls the virtual functions InitFun(), InitConst() and InitOprt().
510 	*/
Init()511 	void ParserBase::Init()
512 	{
513 		InitCharSets();
514 		InitFun();
515 		InitConst();
516 		InitOprt();
517 	}
518 
519 	//---------------------------------------------------------------------------
520 	/** \brief Add a user defined operator.
521 		\post Will reset the Parser to string parsing mode.
522 		\param [in] a_sName  operator Identifier
523 		\param [in] a_pFun  Operator callback function
524 		\param [in] a_iPrec  Operator Precedence (default=prSIGN)
525 		\param [in] a_bAllowOpt  True if operator is volatile (default=false)
526 		\sa EPrec
527 	*/
DefineInfixOprt(const string_type & a_sName,fun_type1 a_pFun,int a_iPrec,bool a_bAllowOpt)528 	void ParserBase::DefineInfixOprt(const string_type& a_sName, fun_type1 a_pFun, int a_iPrec, bool a_bAllowOpt)
529 	{
530 		if (a_sName.length() > MaxLenIdentifier)
531 			Error(ecIDENTIFIER_TOO_LONG);
532 
533 		AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), m_InfixOprtDef, ValidInfixOprtChars());
534 	}
535 
536 
537 	//---------------------------------------------------------------------------
538 	/** \brief Define a binary operator.
539 		\param [in] a_sName The identifier of the operator.
540 		\param [in] a_pFun Pointer to the callback function.
541 		\param [in] a_iPrec Precedence of the operator.
542 		\param [in] a_eAssociativity The associativity of the operator.
543 		\param [in] a_bAllowOpt If this is true the operator may be optimized away.
544 
545 		Adds a new Binary operator the the parser instance.
546 	*/
DefineOprt(const string_type & a_sName,fun_type2 a_pFun,unsigned a_iPrec,EOprtAssociativity a_eAssociativity,bool a_bAllowOpt)547 	void ParserBase::DefineOprt(const string_type& a_sName, fun_type2 a_pFun, unsigned a_iPrec, EOprtAssociativity a_eAssociativity, bool a_bAllowOpt)
548 	{
549 		if (a_sName.length() > MaxLenIdentifier)
550 			Error(ecIDENTIFIER_TOO_LONG);
551 
552 		// Check for conflicts with built in operator names
553 		for (int i = 0; m_bBuiltInOp && i < cmENDIF; ++i)
554 		{
555 			if (a_sName == string_type(c_DefaultOprt[i]))
556 			{
557 				Error(ecBUILTIN_OVERLOAD, -1, a_sName);
558 			}
559 		}
560 
561 		AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, a_eAssociativity), m_OprtDef, ValidOprtChars());
562 	}
563 
564 	//---------------------------------------------------------------------------
565 	/** \brief Define a new string constant.
566 		\param [in] a_strName The name of the constant.
567 		\param [in] a_strVal the value of the constant.
568 	*/
DefineStrConst(const string_type & a_strName,const string_type & a_strVal)569 	void ParserBase::DefineStrConst(const string_type& a_strName, const string_type& a_strVal)
570 	{
571 		// Test if a constant with that names already exists
572 		if (m_StrVarDef.find(a_strName) != m_StrVarDef.end())
573 			Error(ecNAME_CONFLICT);
574 
575 		CheckName(a_strName, ValidNameChars());
576 
577 		m_vStringVarBuf.push_back(a_strVal);                // Store variable string in internal buffer
578 		m_StrVarDef[a_strName] = m_vStringVarBuf.size() - 1;  // bind buffer index to variable name
579 
580 		ReInit();
581 	}
582 
583 	//---------------------------------------------------------------------------
584 	/** \brief Add a user defined variable.
585 		\param [in] a_sName the variable name
586 		\param [in] a_pVar A pointer to the variable value.
587 		\post Will reset the Parser to string parsing mode.
588 		\throw ParserException in case the name contains invalid signs or a_pVar is nullptr.
589 	*/
DefineVar(const string_type & a_sName,value_type * a_pVar)590 	void ParserBase::DefineVar(const string_type& a_sName, value_type* a_pVar)
591 	{
592 		if (a_pVar == 0)
593 			Error(ecINVALID_VAR_PTR);
594 
595 		if (a_sName.length() > MaxLenIdentifier)
596 			Error(ecIDENTIFIER_TOO_LONG);
597 
598 		// Test if a constant with that names already exists
599 		if (m_ConstDef.find(a_sName) != m_ConstDef.end())
600 			Error(ecNAME_CONFLICT);
601 
602 		CheckName(a_sName, ValidNameChars());
603 		m_VarDef[a_sName] = a_pVar;
604 		ReInit();
605 	}
606 
607 	//---------------------------------------------------------------------------
608 	/** \brief Add a user defined constant.
609 		\param [in] a_sName The name of the constant.
610 		\param [in] a_fVal the value of the constant.
611 		\post Will reset the Parser to string parsing mode.
612 		\throw ParserException in case the name contains invalid signs.
613 	*/
DefineConst(const string_type & a_sName,value_type a_fVal)614 	void ParserBase::DefineConst(const string_type& a_sName, value_type a_fVal)
615 	{
616 		if (a_sName.length() > MaxLenIdentifier)
617 			Error(ecIDENTIFIER_TOO_LONG);
618 
619 		CheckName(a_sName, ValidNameChars());
620 		m_ConstDef[a_sName] = a_fVal;
621 		ReInit();
622 	}
623 
624 	//---------------------------------------------------------------------------
625 	/** \brief Get operator priority.
626 		\throw ParserException if a_Oprt is no operator code
627 	*/
GetOprtPrecedence(const token_type & a_Tok) const628 	int ParserBase::GetOprtPrecedence(const token_type& a_Tok) const
629 	{
630 		switch (a_Tok.GetCode())
631 		{
632 			// built in operators
633 		case cmEND:      return -5;
634 		case cmARG_SEP:  return -4;
635 		case cmASSIGN:   return -1;
636 		case cmELSE:
637 		case cmIF:       return  0;
638 		case cmLAND:     return  prLAND;
639 		case cmLOR:      return  prLOR;
640 		case cmLT:
641 		case cmGT:
642 		case cmLE:
643 		case cmGE:
644 		case cmNEQ:
645 		case cmEQ:       return  prCMP;
646 		case cmADD:
647 		case cmSUB:      return  prADD_SUB;
648 		case cmMUL:
649 		case cmDIV:      return  prMUL_DIV;
650 		case cmPOW:      return  prPOW;
651 
652 			// user defined binary operators
653 		case cmOPRT_INFIX:
654 		case cmOPRT_BIN: return a_Tok.GetPri();
655 		default:  Error(ecINTERNAL_ERROR, 5);
656 			return 999;
657 		}
658 	}
659 
660 	//---------------------------------------------------------------------------
661 	/** \brief Get operator priority.
662 		\throw ParserException if a_Oprt is no operator code
663 	*/
GetOprtAssociativity(const token_type & a_Tok) const664 	EOprtAssociativity ParserBase::GetOprtAssociativity(const token_type& a_Tok) const
665 	{
666 		switch (a_Tok.GetCode())
667 		{
668 		case cmASSIGN:
669 		case cmLAND:
670 		case cmLOR:
671 		case cmLT:
672 		case cmGT:
673 		case cmLE:
674 		case cmGE:
675 		case cmNEQ:
676 		case cmEQ:
677 		case cmADD:
678 		case cmSUB:
679 		case cmMUL:
680 		case cmDIV:      return oaLEFT;
681 		case cmPOW:      return oaRIGHT;
682 		case cmOPRT_BIN: return a_Tok.GetAssociativity();
683 		default:         return oaNONE;
684 		}
685 	}
686 
687 	//---------------------------------------------------------------------------
688 	/** \brief Return a map containing the used variables only. */
GetUsedVar() const689 	const varmap_type& ParserBase::GetUsedVar() const
690 	{
691 		try
692 		{
693 			m_pTokenReader->IgnoreUndefVar(true);
694 			CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it
695 						 // may contain references to nonexisting variables.
696 			m_pParseFormula = &ParserBase::ParseString;
697 			m_pTokenReader->IgnoreUndefVar(false);
698 		}
699 		catch (exception_type& /*e*/)
700 		{
701 			// Make sure to stay in string parse mode, don't call ReInit()
702 			// because it deletes the array with the used variables
703 			m_pParseFormula = &ParserBase::ParseString;
704 			m_pTokenReader->IgnoreUndefVar(false);
705 			throw;
706 		}
707 
708 		return m_pTokenReader->GetUsedVar();
709 	}
710 
711 	//---------------------------------------------------------------------------
712 	/** \brief Return a map containing the used variables only. */
GetVar() const713 	const varmap_type& ParserBase::GetVar() const
714 	{
715 		return m_VarDef;
716 	}
717 
718 	//---------------------------------------------------------------------------
719 	/** \brief Return a map containing all parser constants. */
GetConst() const720 	const valmap_type& ParserBase::GetConst() const
721 	{
722 		return m_ConstDef;
723 	}
724 
725 	//---------------------------------------------------------------------------
726 	/** \brief Return prototypes of all parser functions.
727 		\return #m_FunDef
728 		\sa FunProt
729 		\throw nothrow
730 
731 		The return type is a map of the public type #funmap_type containing the prototype
732 		definitions for all numerical parser functions. String functions are not part of
733 		this map. The Prototype definition is encapsulated in objects of the class FunProt
734 		one per parser function each associated with function names via a map construct.
735 	*/
GetFunDef() const736 	const funmap_type& ParserBase::GetFunDef() const
737 	{
738 		return m_FunDef;
739 	}
740 
741 	//---------------------------------------------------------------------------
742 	/** \brief Retrieve the formula. */
GetExpr() const743 	const string_type& ParserBase::GetExpr() const
744 	{
745 		return m_pTokenReader->GetExpr();
746 	}
747 
748 	//---------------------------------------------------------------------------
749 	/** \brief Execute a function that takes a single string argument.
750 		\param a_FunTok Function token.
751 		\throw exception_type If the function token is not a string function
752 	*/
ApplyStrFunc(const token_type & a_FunTok,const std::vector<token_type> & a_vArg) const753 	ParserBase::token_type ParserBase::ApplyStrFunc(const token_type& a_FunTok,
754 		const std::vector<token_type>& a_vArg) const
755 	{
756 		if (a_vArg.back().GetCode() != cmSTRING)
757 			Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
758 
759 		token_type  valTok;
760 		generic_fun_type pFunc = a_FunTok.GetFuncAddr();
761 		MUP_ASSERT(pFunc);
762 
763 		try
764 		{
765 			// Check function arguments; write dummy value into valtok to represent the result
766 			switch (a_FunTok.GetArgCount())
767 			{
768 			case 0: valTok.SetVal(1); a_vArg[0].GetAsString();  break;
769 			case 1: valTok.SetVal(1); a_vArg[1].GetAsString();  a_vArg[0].GetVal();  break;
770 			case 2: valTok.SetVal(1); a_vArg[2].GetAsString();  a_vArg[1].GetVal();  a_vArg[0].GetVal();  break;
771 			case 3: valTok.SetVal(1); a_vArg[3].GetAsString();  a_vArg[2].GetVal();  a_vArg[1].GetVal();  a_vArg[0].GetVal();  break;
772 			case 4: valTok.SetVal(1); a_vArg[4].GetAsString();  a_vArg[3].GetVal();  a_vArg[2].GetVal();  a_vArg[1].GetVal();  a_vArg[0].GetVal();  break;
773 			default: Error(ecINTERNAL_ERROR);
774 			}
775 		}
776 		catch (ParserError&)
777 		{
778 			Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
779 		}
780 
781 		// string functions won't be optimized
782 		m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx());
783 
784 		// Push dummy value representing the function result to the stack
785 		return valTok;
786 	}
787 
788 	//---------------------------------------------------------------------------
789 	/** \brief Apply a function token.
790 		\param iArgCount Number of Arguments actually gathered used only for multiarg functions.
791 		\post The result is pushed to the value stack
792 		\post The function token is removed from the stack
793 		\throw exception_type if Argument count does not match function requirements.
794 	*/
ApplyFunc(std::stack<token_type> & a_stOpt,std::stack<token_type> & a_stVal,int a_iArgCount) const795 	void ParserBase::ApplyFunc(std::stack<token_type>& a_stOpt, std::stack<token_type>& a_stVal, int a_iArgCount) const
796 	{
797 		MUP_ASSERT(m_pTokenReader.get());
798 
799 		// Operator stack empty or does not contain tokens with callback functions
800 		if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr() == 0)
801 			return;
802 
803 		token_type funTok = a_stOpt.top();
804 		a_stOpt.pop();
805 		MUP_ASSERT(funTok.GetFuncAddr() != nullptr);
806 
807 		// Binary operators must rely on their internal operator number
808 		// since counting of operators relies on commas for function arguments
809 		// binary operators do not have commas in their expression
810 		int iArgCount = (funTok.GetCode() == cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount;
811 
812 		// determine how many parameters the function needs. To remember iArgCount includes the
813 		// string parameter whilst GetArgCount() counts only numeric parameters.
814 		int iArgRequired = funTok.GetArgCount() + ((funTok.GetType() == tpSTR) ? 1 : 0);
815 
816 		// That's the number of numerical parameters
817 		int iArgNumerical = iArgCount - ((funTok.GetType() == tpSTR) ? 1 : 0);
818 
819 		if (funTok.GetCode() == cmFUNC_STR && iArgCount - iArgNumerical > 1)
820 			Error(ecINTERNAL_ERROR);
821 
822 		if (funTok.GetArgCount() >= 0 && iArgCount > iArgRequired)
823 			Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString());
824 
825 		if (funTok.GetCode() != cmOPRT_BIN && iArgCount < iArgRequired)
826 			Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString());
827 
828 		if (funTok.GetCode() == cmFUNC_STR && iArgCount > iArgRequired)
829 			Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString());
830 
831 		// Collect the numeric function arguments from the value stack and store them
832 		// in a vector
833 		std::vector<token_type> stArg;
834 		for (int i = 0; i < iArgNumerical; ++i)
835 		{
836 			if (a_stVal.empty())
837 				Error(ecINTERNAL_ERROR, m_pTokenReader->GetPos(), funTok.GetAsString());
838 
839 			stArg.push_back(a_stVal.top());
840 			a_stVal.pop();
841 
842 			if (stArg.back().GetType() == tpSTR && funTok.GetType() != tpSTR)
843 				Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
844 		}
845 
846 		switch (funTok.GetCode())
847 		{
848 		case  cmFUNC_STR:
849 			if (a_stVal.empty())
850 				Error(ecINTERNAL_ERROR, m_pTokenReader->GetPos(), funTok.GetAsString());
851 
852 			stArg.push_back(a_stVal.top());
853 			a_stVal.pop();
854 
855 			if (stArg.back().GetType() == tpSTR && funTok.GetType() != tpSTR)
856 				Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
857 
858 			ApplyStrFunc(funTok, stArg);
859 			break;
860 
861 		case  cmFUNC_BULK:
862 			m_vRPN.AddBulkFun(funTok.GetFuncAddr(), (int)stArg.size());
863 			break;
864 
865 		case  cmOPRT_BIN:
866 		case  cmOPRT_POSTFIX:
867 		case  cmOPRT_INFIX:
868 		case  cmFUNC:
869 			if (funTok.GetArgCount() == -1 && iArgCount == 0)
870 				Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString());
871 
872 			m_vRPN.AddFun(funTok.GetFuncAddr(), (funTok.GetArgCount() == -1) ? -iArgNumerical : iArgNumerical);
873 			break;
874 		default:
875 			break;
876 		}
877 
878 		// Push dummy value representing the function result to the stack
879 		token_type token;
880 		token.SetVal(1);
881 		a_stVal.push(token);
882 	}
883 
884 	//---------------------------------------------------------------------------
ApplyIfElse(std::stack<token_type> & a_stOpt,std::stack<token_type> & a_stVal) const885 	void ParserBase::ApplyIfElse(std::stack<token_type>& a_stOpt, std::stack<token_type>& a_stVal) const
886 	{
887 		// Check if there is an if Else clause to be calculated
888 		while (a_stOpt.size() && a_stOpt.top().GetCode() == cmELSE)
889 		{
890 			MUP_ASSERT(!a_stOpt.empty())
891 				token_type opElse = a_stOpt.top();
892 			a_stOpt.pop();
893 
894 			// Take the value associated with the else branch from the value stack
895 			MUP_ASSERT(!a_stVal.empty());
896 			token_type vVal2 = a_stVal.top();
897 			a_stVal.pop();
898 
899 			// it then else is a ternary operator Pop all three values from the value s
900 			// tack and just return the right value
901 			MUP_ASSERT(!a_stVal.empty());
902 			token_type vVal1 = a_stVal.top();
903 			a_stVal.pop();
904 
905 			MUP_ASSERT(!a_stVal.empty());
906 			token_type vExpr = a_stVal.top();
907 			a_stVal.pop();
908 
909 			a_stVal.push((vExpr.GetVal() != 0) ? vVal1 : vVal2);
910 
911 			token_type opIf = a_stOpt.top();
912 			a_stOpt.pop();
913 
914 			MUP_ASSERT(opElse.GetCode() == cmELSE);
915 
916 			if (opIf.GetCode() != cmIF)
917 				Error(ecMISPLACED_COLON, m_pTokenReader->GetPos());
918 
919 			m_vRPN.AddIfElse(cmENDIF);
920 		} // while pending if-else-clause found
921 	}
922 
923 	//---------------------------------------------------------------------------
924 	/** \brief Performs the necessary steps to write code for
925 			   the execution of binary operators into the bytecode.
926 	*/
ApplyBinOprt(std::stack<token_type> & a_stOpt,std::stack<token_type> & a_stVal) const927 	void ParserBase::ApplyBinOprt(std::stack<token_type>& a_stOpt, std::stack<token_type>& a_stVal) const
928 	{
929 		// is it a user defined binary operator?
930 		if (a_stOpt.top().GetCode() == cmOPRT_BIN)
931 		{
932 			ApplyFunc(a_stOpt, a_stVal, 2);
933 		}
934 		else
935 		{
936 			if (a_stVal.size() < 2)
937 				Error(ecINTERNAL_ERROR, m_pTokenReader->GetPos(), _T("ApplyBinOprt: not enough values in value stack!"));
938 
939 			token_type valTok1 = a_stVal.top();
940 			a_stVal.pop();
941 
942 			token_type valTok2 = a_stVal.top();
943 			a_stVal.pop();
944 
945 			token_type optTok = a_stOpt.top();
946 			a_stOpt.pop();
947 
948 			token_type resTok;
949 
950 			if (valTok1.GetType() != valTok2.GetType() ||
951 				(valTok1.GetType() == tpSTR && valTok2.GetType() == tpSTR))
952 				Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString());
953 
954 			if (optTok.GetCode() == cmASSIGN)
955 			{
956 				if (valTok2.GetCode() != cmVAR)
957 					Error(ecUNEXPECTED_OPERATOR, -1, _T("="));
958 
959 				m_vRPN.AddAssignOp(valTok2.GetVar());
960 			}
961 			else
962 				m_vRPN.AddOp(optTok.GetCode());
963 
964 			resTok.SetVal(1);
965 			a_stVal.push(resTok);
966 		}
967 	}
968 
969 	//---------------------------------------------------------------------------
970 	/** \brief Apply a binary operator.
971 		\param a_stOpt The operator stack
972 		\param a_stVal The value stack
973 	*/
ApplyRemainingOprt(std::stack<token_type> & stOpt,std::stack<token_type> & stVal) const974 	void ParserBase::ApplyRemainingOprt(std::stack<token_type>& stOpt, std::stack<token_type>& stVal) const
975 	{
976 		while (stOpt.size() &&
977 			stOpt.top().GetCode() != cmBO &&
978 			stOpt.top().GetCode() != cmIF)
979 		{
980 			token_type tok = stOpt.top();
981 			switch (tok.GetCode())
982 			{
983 			case cmOPRT_INFIX:
984 			case cmOPRT_BIN:
985 			case cmLE:
986 			case cmGE:
987 			case cmNEQ:
988 			case cmEQ:
989 			case cmLT:
990 			case cmGT:
991 			case cmADD:
992 			case cmSUB:
993 			case cmMUL:
994 			case cmDIV:
995 			case cmPOW:
996 			case cmLAND:
997 			case cmLOR:
998 			case cmASSIGN:
999 				if (stOpt.top().GetCode() == cmOPRT_INFIX)
1000 					ApplyFunc(stOpt, stVal, 1);
1001 				else
1002 					ApplyBinOprt(stOpt, stVal);
1003 				break;
1004 
1005 			case cmELSE:
1006 				ApplyIfElse(stOpt, stVal);
1007 				break;
1008 
1009 			default:
1010 				Error(ecINTERNAL_ERROR);
1011 			}
1012 		}
1013 	}
1014 
1015 	//---------------------------------------------------------------------------
1016 	/** \brief Parse the command code.
1017 		\sa ParseString(...)
1018 
1019 		Command code contains precalculated stack positions of the values and the
1020 		associated operators. The Stack is filled beginning from index one the
1021 		value at index zero is not used at all.
1022 	*/
ParseCmdCode() const1023 	value_type ParserBase::ParseCmdCode() const
1024 	{
1025 		return ParseCmdCodeBulk(0, 0);
1026 	}
1027 
ParseCmdCodeShort() const1028 	value_type ParserBase::ParseCmdCodeShort() const
1029 	{
1030 		const SToken *const tok = m_vRPN.GetBase();
1031 		value_type buf;
1032 
1033 		switch (tok->Cmd)
1034 		{
1035 		case cmVAL:
1036 			return tok->Val.data2;
1037 
1038 		case cmVAR:
1039 			return *tok->Val.ptr;
1040 
1041 		case cmVARMUL:
1042 			return *tok->Val.ptr * tok->Val.data + tok->Val.data2;
1043 
1044 		case cmVARPOW2:
1045 			buf = *(tok->Val.ptr);
1046 			return buf * buf;
1047 
1048 		case  cmVARPOW3:
1049 			buf = *(tok->Val.ptr);
1050 			return buf * buf * buf;
1051 
1052 		case  cmVARPOW4:
1053 			buf = *(tok->Val.ptr);
1054 			return buf * buf * buf * buf;
1055 
1056 		// numerical function without any argument
1057 		case cmFUNC:
1058 			return (*(fun_type0)tok->Fun.ptr)();
1059 
1060 		// String function without a numerical argument
1061 		case cmFUNC_STR:
1062 			return (*(strfun_type1)tok->Fun.ptr)(m_vStringBuf[0].c_str());
1063 
1064 		default:
1065 			throw ParserError(ecINTERNAL_ERROR);
1066 		}
1067 	}
1068 
1069 	//---------------------------------------------------------------------------
1070 	/** \brief Evaluate the RPN.
1071 		\param nOffset The offset added to variable addresses (for bulk mode)
1072 		\param nThreadID OpenMP Thread id of the calling thread
1073 	*/
ParseCmdCodeBulk(int nOffset,int nThreadID) const1074 	value_type ParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const
1075 	{
1076 		assert(nThreadID <= s_MaxNumOpenMPThreads);
1077 
1078 		// Note: The check for nOffset==0 and nThreadID here is not necessary but
1079 		//       brings a minor performance gain when not in bulk mode.
1080 		value_type* Stack = ((nOffset == 0) && (nThreadID == 0)) ? &m_vStackBuffer[0] : &m_vStackBuffer[nThreadID * (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)];
1081 		value_type buf;
1082 		int sidx(0);
1083 		for (const SToken* pTok = m_vRPN.GetBase(); pTok->Cmd != cmEND; ++pTok)
1084 		{
1085 			switch (pTok->Cmd)
1086 			{
1087 			// built in binary operators
1088 			case  cmLE:   --sidx; Stack[sidx] = Stack[sidx] <= Stack[sidx + 1]; continue;
1089 			case  cmGE:   --sidx; Stack[sidx] = Stack[sidx] >= Stack[sidx + 1]; continue;
1090 			case  cmNEQ:  --sidx; Stack[sidx] = Stack[sidx] != Stack[sidx + 1]; continue;
1091 			case  cmEQ:   --sidx; Stack[sidx] = Stack[sidx] == Stack[sidx + 1]; continue;
1092 			case  cmLT:   --sidx; Stack[sidx] = Stack[sidx] < Stack[sidx + 1];  continue;
1093 			case  cmGT:   --sidx; Stack[sidx] = Stack[sidx] > Stack[sidx + 1];  continue;
1094 			case  cmADD:  --sidx; Stack[sidx] += Stack[1 + sidx]; continue;
1095 			case  cmSUB:  --sidx; Stack[sidx] -= Stack[1 + sidx]; continue;
1096 			case  cmMUL:  --sidx; Stack[sidx] *= Stack[1 + sidx]; continue;
1097 			case  cmDIV:  --sidx;
1098 				Stack[sidx] /= Stack[1 + sidx];
1099 				continue;
1100 
1101 			case  cmPOW:
1102 				--sidx; Stack[sidx] = MathImpl<value_type>::Pow(Stack[sidx], Stack[1 + sidx]);
1103 				continue;
1104 
1105 			case  cmLAND: --sidx; Stack[sidx] = Stack[sidx] && Stack[sidx + 1]; continue;
1106 			case  cmLOR:  --sidx; Stack[sidx] = Stack[sidx] || Stack[sidx + 1]; continue;
1107 
1108 			case  cmASSIGN:
1109 				// Bugfix for Bulkmode:
1110 				// for details see:
1111 				//    https://groups.google.com/forum/embed/?place=forum/muparser-dev&showsearch=true&showpopout=true&showtabs=false&parenturl=http://muparser.beltoforion.de/mup_forum.html&afterlogin&pli=1#!topic/muparser-dev/szgatgoHTws
1112 				--sidx; Stack[sidx] = *(pTok->Oprt.ptr + nOffset) = Stack[sidx + 1]; continue;
1113 				// original code:
1114 				//--sidx; Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; continue;
1115 
1116 			case  cmIF:
1117 				if (Stack[sidx--] == 0)
1118 				{
1119 					MUP_ASSERT(sidx >= 0);
1120 					pTok += pTok->Oprt.offset;
1121 				}
1122 				continue;
1123 
1124 			case  cmELSE:
1125 				pTok += pTok->Oprt.offset;
1126 				continue;
1127 
1128 			case  cmENDIF:
1129 				continue;
1130 
1131 				// value and variable tokens
1132 			case  cmVAR:    Stack[++sidx] = *(pTok->Val.ptr + nOffset);  continue;
1133 			case  cmVAL:    Stack[++sidx] = pTok->Val.data2;  continue;
1134 
1135 			case  cmVARPOW2: buf = *(pTok->Val.ptr + nOffset);
1136 				Stack[++sidx] = buf * buf;
1137 				continue;
1138 
1139 			case  cmVARPOW3: buf = *(pTok->Val.ptr + nOffset);
1140 				Stack[++sidx] = buf * buf * buf;
1141 				continue;
1142 
1143 			case  cmVARPOW4: buf = *(pTok->Val.ptr + nOffset);
1144 				Stack[++sidx] = buf * buf * buf * buf;
1145 				continue;
1146 
1147 			case  cmVARMUL:
1148 				Stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2;
1149 				continue;
1150 
1151 				// Next is treatment of numeric functions
1152 			case  cmFUNC:
1153 			{
1154 				int iArgCount = pTok->Fun.argc;
1155 
1156 				// switch according to argument count
1157 				switch (iArgCount)
1158 				{
1159 				case 0: sidx += 1; Stack[sidx] = (*(fun_type0)pTok->Fun.ptr)(); continue;
1160 				case 1:            Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(Stack[sidx]);   continue;
1161 				case 2: sidx -= 1; Stack[sidx] = (*(fun_type2)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1]); continue;
1162 				case 3: sidx -= 2; Stack[sidx] = (*(fun_type3)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1], Stack[sidx + 2]); continue;
1163 				case 4: sidx -= 3; Stack[sidx] = (*(fun_type4)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3]); continue;
1164 				case 5: sidx -= 4; Stack[sidx] = (*(fun_type5)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4]); continue;
1165 				case 6: sidx -= 5; Stack[sidx] = (*(fun_type6)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5]); continue;
1166 				case 7: sidx -= 6; Stack[sidx] = (*(fun_type7)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6]); continue;
1167 				case 8: sidx -= 7; Stack[sidx] = (*(fun_type8)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6], Stack[sidx + 7]); continue;
1168 				case 9: sidx -= 8; Stack[sidx] = (*(fun_type9)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6], Stack[sidx + 7], Stack[sidx + 8]); continue;
1169 				case 10:sidx -= 9; Stack[sidx] = (*(fun_type10)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6], Stack[sidx + 7], Stack[sidx + 8], Stack[sidx + 9]); continue;
1170 				default:
1171 					// function with variable arguments store the number as a negative value
1172 					if (iArgCount > 0)
1173 						Error(ecINTERNAL_ERROR, -1);
1174 
1175 					sidx -= -iArgCount - 1;
1176 
1177 					// <ibg 2020-06-08/> From oss-fuzz. Happend when Multiarg functions and if-then-else are used incorrectly "sum(0?1,2,3,4,5:6)"
1178 					// The final result normally lieas at position 1. If sixd is smaller there is something wrong.
1179 					if (sidx <= 0)
1180 						Error(ecINTERNAL_ERROR, -1);
1181 
1182 					Stack[sidx] = (*(multfun_type)pTok->Fun.ptr)(&Stack[sidx], -iArgCount);
1183 					continue;
1184 				}
1185 			}
1186 
1187 			// Next is treatment of string functions
1188 			case  cmFUNC_STR:
1189 			{
1190 				sidx -= pTok->Fun.argc - 1;
1191 
1192 				// The index of the string argument in the string table
1193 				int iIdxStack = pTok->Fun.idx;
1194 				if (iIdxStack < 0 || iIdxStack >= (int)m_vStringBuf.size())
1195 					Error(ecINTERNAL_ERROR, m_pTokenReader->GetPos());
1196 
1197 				switch (pTok->Fun.argc)  // switch according to argument count
1198 				{
1199 				case 0: Stack[sidx] = (*(strfun_type1)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str()); continue;
1200 				case 1: Stack[sidx] = (*(strfun_type2)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx]); continue;
1201 				case 2: Stack[sidx] = (*(strfun_type3)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx + 1]); continue;
1202 				case 3: Stack[sidx] = (*(strfun_type4)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx + 1], Stack[sidx + 2]); continue;
1203 				case 4: Stack[sidx] = (*(strfun_type5)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3]); continue;
1204 				}
1205 
1206 				continue;
1207 			}
1208 
1209 			case  cmFUNC_BULK:
1210 			{
1211 				int iArgCount = pTok->Fun.argc;
1212 
1213 				// switch according to argument count
1214 				switch (iArgCount)
1215 				{
1216 				case 0: sidx += 1; Stack[sidx] = (*(bulkfun_type0)pTok->Fun.ptr)(nOffset, nThreadID); continue;
1217 				case 1:            Stack[sidx] = (*(bulkfun_type1)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx]); continue;
1218 				case 2: sidx -= 1; Stack[sidx] = (*(bulkfun_type2)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx + 1]); continue;
1219 				case 3: sidx -= 2; Stack[sidx] = (*(bulkfun_type3)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx + 1], Stack[sidx + 2]); continue;
1220 				case 4: sidx -= 3; Stack[sidx] = (*(bulkfun_type4)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3]); continue;
1221 				case 5: sidx -= 4; Stack[sidx] = (*(bulkfun_type5)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4]); continue;
1222 				case 6: sidx -= 5; Stack[sidx] = (*(bulkfun_type6)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5]); continue;
1223 				case 7: sidx -= 6; Stack[sidx] = (*(bulkfun_type7)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6]); continue;
1224 				case 8: sidx -= 7; Stack[sidx] = (*(bulkfun_type8)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6], Stack[sidx + 7]); continue;
1225 				case 9: sidx -= 8; Stack[sidx] = (*(bulkfun_type9)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6], Stack[sidx + 7], Stack[sidx + 8]); continue;
1226 				case 10:sidx -= 9; Stack[sidx] = (*(bulkfun_type10)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6], Stack[sidx + 7], Stack[sidx + 8], Stack[sidx + 9]); continue;
1227 				default:
1228 					Error(ecINTERNAL_ERROR, 2);
1229 					continue;
1230 				}
1231 			}
1232 
1233 			default:
1234 				Error(ecINTERNAL_ERROR, 3);
1235 				return 0;
1236 			} // switch CmdCode
1237 		} // for all bytecode tokens
1238 
1239 		return Stack[m_nFinalResultIdx];
1240 	}
1241 
1242 	//---------------------------------------------------------------------------
CreateRPN() const1243 	void ParserBase::CreateRPN() const
1244 	{
1245 		if (!m_pTokenReader->GetExpr().length())
1246 			Error(ecUNEXPECTED_EOF, 0);
1247 
1248 		std::stack<token_type> stOpt, stVal;
1249 		std::stack<int> stArgCount;
1250 		token_type opta, opt;  // for storing operators
1251 		token_type val, tval;  // for storing value
1252 		int ifElseCounter = 0;
1253 
1254 		ReInit();
1255 
1256 		// The outermost counter counts the number of separated items
1257 		// such as in "a=10,b=20,c=c+a"
1258 		stArgCount.push(1);
1259 
1260 		for (;;)
1261 		{
1262 			opt = m_pTokenReader->ReadNextToken();
1263 
1264 			switch (opt.GetCode())
1265 			{
1266 			//
1267 			// Next three are different kind of value entries
1268 			//
1269 			case cmSTRING:
1270 				if (stOpt.empty())
1271 					Error(ecSTR_RESULT, m_pTokenReader->GetPos(), opt.GetAsString());
1272 
1273 				opt.SetIdx((int)m_vStringBuf.size());      // Assign buffer index to token
1274 				stVal.push(opt);
1275 				m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer
1276 				break;
1277 
1278 			case cmVAR:
1279 				stVal.push(opt);
1280 				m_vRPN.AddVar(static_cast<value_type*>(opt.GetVar()));
1281 				break;
1282 
1283 			case cmVAL:
1284 				stVal.push(opt);
1285 				m_vRPN.AddVal(opt.GetVal());
1286 				break;
1287 
1288 			case cmELSE:
1289 				if (stArgCount.empty())
1290 					Error(ecMISPLACED_COLON, m_pTokenReader->GetPos());
1291 
1292 				if (stArgCount.top() > 1)
1293 					Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos());
1294 
1295 				stArgCount.pop();
1296 
1297 				ifElseCounter--;
1298 				if (ifElseCounter < 0)
1299 					Error(ecMISPLACED_COLON, m_pTokenReader->GetPos());
1300 
1301 				ApplyRemainingOprt(stOpt, stVal);
1302 				m_vRPN.AddIfElse(cmELSE);
1303 				stOpt.push(opt);
1304 				break;
1305 
1306 			case cmARG_SEP:
1307 				if (!stOpt.empty() && stOpt.top().GetCode() == cmIF)
1308 					Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos());
1309 
1310 				if (stArgCount.empty())
1311 					Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos());
1312 
1313 				++stArgCount.top();
1314 				// Falls through.
1315 				// intentional (no break!)
1316 
1317 			case cmEND:
1318 				ApplyRemainingOprt(stOpt, stVal);
1319 				break;
1320 
1321 			case cmBC:
1322 			{
1323 				// The argument count for parameterless functions is zero
1324 				// by default an opening bracket sets parameter count to 1
1325 				// in preparation of arguments to come. If the last token
1326 				// was an opening bracket we know better...
1327 				if (opta.GetCode() == cmBO)
1328 					--stArgCount.top();
1329 
1330 				ApplyRemainingOprt(stOpt, stVal);
1331 
1332 				// Check if the bracket content has been evaluated completely
1333 				if (stOpt.size() && stOpt.top().GetCode() == cmBO)
1334 				{
1335 					// if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check
1336 					// if there is either a function or a sign pending
1337 					// neither the opening nor the closing bracket will be pushed back to
1338 					// the operator stack
1339 					// Check if a function is standing in front of the opening bracket,
1340 					// if yes evaluate it afterwards check for infix operators
1341 					MUP_ASSERT(stArgCount.size());
1342 					int iArgCount = stArgCount.top();
1343 					stArgCount.pop();
1344 
1345 					stOpt.pop(); // Take opening bracket from stack
1346 
1347 					if (iArgCount > 1 && (stOpt.size() == 0 ||
1348 						(stOpt.top().GetCode() != cmFUNC &&
1349 							stOpt.top().GetCode() != cmFUNC_BULK &&
1350 							stOpt.top().GetCode() != cmFUNC_STR)))
1351 						Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos());
1352 
1353 					// The opening bracket was popped from the stack now check if there
1354 					// was a function before this bracket
1355 					if (stOpt.size() &&
1356 						stOpt.top().GetCode() != cmOPRT_INFIX &&
1357 						stOpt.top().GetCode() != cmOPRT_BIN &&
1358 						stOpt.top().GetFuncAddr() != 0)
1359 					{
1360 						ApplyFunc(stOpt, stVal, iArgCount);
1361 					}
1362 				}
1363 			} // if bracket content is evaluated
1364 			break;
1365 
1366 			//
1367 			// Next are the binary operator entries
1368 			//
1369 			case cmIF:
1370 				ifElseCounter++;
1371 				stArgCount.push(1);
1372 				// Falls through.
1373 				// intentional (no break!)
1374 
1375 			case cmLAND:
1376 			case cmLOR:
1377 			case cmLT:
1378 			case cmGT:
1379 			case cmLE:
1380 			case cmGE:
1381 			case cmNEQ:
1382 			case cmEQ:
1383 			case cmADD:
1384 			case cmSUB:
1385 			case cmMUL:
1386 			case cmDIV:
1387 			case cmPOW:
1388 			case cmASSIGN:
1389 			case cmOPRT_BIN:
1390 
1391 				// A binary operator (user defined or built in) has been found.
1392 				while (
1393 					stOpt.size() &&
1394 					stOpt.top().GetCode() != cmBO &&
1395 					stOpt.top().GetCode() != cmELSE &&
1396 					stOpt.top().GetCode() != cmIF)
1397 				{
1398 					int nPrec1 = GetOprtPrecedence(stOpt.top()),
1399 						nPrec2 = GetOprtPrecedence(opt);
1400 
1401 					if (stOpt.top().GetCode() == opt.GetCode())
1402 					{
1403 
1404 						// Deal with operator associativity
1405 						EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt);
1406 						if ((eOprtAsct == oaRIGHT && (nPrec1 <= nPrec2)) ||
1407 							(eOprtAsct == oaLEFT && (nPrec1 < nPrec2)))
1408 						{
1409 							break;
1410 						}
1411 					}
1412 					else if (nPrec1 < nPrec2)
1413 					{
1414 						// In case the operators are not equal the precedence decides alone...
1415 						break;
1416 					}
1417 
1418 					if (stOpt.top().GetCode() == cmOPRT_INFIX)
1419 						ApplyFunc(stOpt, stVal, 1);
1420 					else
1421 						ApplyBinOprt(stOpt, stVal);
1422 				} // while ( ... )
1423 
1424 				if (opt.GetCode() == cmIF)
1425 					m_vRPN.AddIfElse(opt.GetCode());
1426 
1427 				// The operator can't be evaluated right now, push back to the operator stack
1428 				stOpt.push(opt);
1429 				break;
1430 
1431 				//
1432 				// Last section contains functions and operators implicitly mapped to functions
1433 				//
1434 			case cmBO:
1435 				stArgCount.push(1);
1436 				stOpt.push(opt);
1437 				break;
1438 
1439 			case cmOPRT_INFIX:
1440 			case cmFUNC:
1441 			case cmFUNC_BULK:
1442 			case cmFUNC_STR:
1443 				stOpt.push(opt);
1444 				break;
1445 
1446 			case cmOPRT_POSTFIX:
1447 				stOpt.push(opt);
1448 				ApplyFunc(stOpt, stVal, 1);  // this is the postfix operator
1449 				break;
1450 
1451 			default:  Error(ecINTERNAL_ERROR, 3);
1452 			} // end of switch operator-token
1453 
1454 			opta = opt;
1455 
1456 			if (opt.GetCode() == cmEND)
1457 			{
1458 				m_vRPN.Finalize();
1459 				break;
1460 			}
1461 
1462 			if (ParserBase::g_DbgDumpStack)
1463 			{
1464 				StackDump(stVal, stOpt);
1465 				m_vRPN.AsciiDump();
1466 			}
1467 
1468 //			if (ParserBase::g_DbgDumpCmdCode)
1469 				//m_vRPN.AsciiDump();
1470 		} // while (true)
1471 
1472 		if (ParserBase::g_DbgDumpCmdCode)
1473 			m_vRPN.AsciiDump();
1474 
1475 		if (ifElseCounter > 0)
1476 			Error(ecMISSING_ELSE_CLAUSE);
1477 
1478 		// get the last value (= final result) from the stack
1479 		MUP_ASSERT(stArgCount.size() == 1);
1480 		m_nFinalResultIdx = stArgCount.top();
1481 		if (m_nFinalResultIdx == 0)
1482 			Error(ecINTERNAL_ERROR, 9);
1483 
1484 		if (stVal.size() == 0)
1485 			Error(ecEMPTY_EXPRESSION);
1486 
1487 		if (stVal.top().GetType() != tpDBL)
1488 			Error(ecSTR_RESULT);
1489 
1490 		m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads);
1491 	}
1492 
1493 	//---------------------------------------------------------------------------
1494 	/** \brief One of the two main parse functions.
1495 		\sa ParseCmdCode(...)
1496 
1497 	  Parse expression from input string. Perform syntax checking and create
1498 	  bytecode. After parsing the string and creating the bytecode the function
1499 	  pointer #m_pParseFormula will be changed to the second parse routine the
1500 	  uses bytecode instead of string parsing.
1501 	*/
ParseString() const1502 	value_type ParserBase::ParseString() const
1503 	{
1504 		try
1505 		{
1506 			CreateRPN();
1507 
1508 			if (m_vRPN.GetSize() == 2)
1509 			{
1510 				m_pParseFormula = &ParserBase::ParseCmdCodeShort;
1511 			}
1512 			else
1513 			{
1514 				m_pParseFormula = &ParserBase::ParseCmdCode;
1515 			}
1516 
1517 			return (this->*m_pParseFormula)();
1518 		}
1519 		catch (ParserError& exc)
1520 		{
1521 			exc.SetFormula(m_pTokenReader->GetExpr());
1522 			throw;
1523 		}
1524 	}
1525 
1526 	//---------------------------------------------------------------------------
1527 	/** \brief Create an error containing the parse error position.
1528 
1529 	  This function will create an Parser Exception object containing the error text and
1530 	  its position.
1531 
1532 	  \param a_iErrc [in] The error code of type #EErrorCodes.
1533 	  \param a_iPos [in] The position where the error was detected.
1534 	  \param a_strTok [in] The token string representation associated with the error.
1535 	  \throw ParserException always throws that's the only purpose of this function.
1536 	*/
Error(EErrorCodes a_iErrc,int a_iPos,const string_type & a_sTok) const1537 	void  ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type& a_sTok) const
1538 	{
1539 		throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos);
1540 	}
1541 
1542 	//------------------------------------------------------------------------------
1543 	/** \brief Clear all user defined variables.
1544 		\throw nothrow
1545 
1546 		Resets the parser to string parsing mode by calling #ReInit.
1547 	*/
ClearVar()1548 	void ParserBase::ClearVar()
1549 	{
1550 		m_VarDef.clear();
1551 		ReInit();
1552 	}
1553 
1554 	//------------------------------------------------------------------------------
1555 	/** \brief Remove a variable from internal storage.
1556 		\throw nothrow
1557 
1558 		Removes a variable if it exists. If the Variable does not exist nothing will be done.
1559 	*/
RemoveVar(const string_type & a_strVarName)1560 	void ParserBase::RemoveVar(const string_type& a_strVarName)
1561 	{
1562 		varmap_type::iterator item = m_VarDef.find(a_strVarName);
1563 		if (item != m_VarDef.end())
1564 		{
1565 			m_VarDef.erase(item);
1566 			ReInit();
1567 		}
1568 	}
1569 
1570 	//------------------------------------------------------------------------------
1571 	/** \brief Clear all functions.
1572 		\post Resets the parser to string parsing mode.
1573 		\throw nothrow
1574 	*/
ClearFun()1575 	void ParserBase::ClearFun()
1576 	{
1577 		m_FunDef.clear();
1578 		ReInit();
1579 	}
1580 
1581 	//------------------------------------------------------------------------------
1582 	/** \brief Clear all user defined constants.
1583 
1584 		Both numeric and string constants will be removed from the internal storage.
1585 		\post Resets the parser to string parsing mode.
1586 		\throw nothrow
1587 	*/
ClearConst()1588 	void ParserBase::ClearConst()
1589 	{
1590 		m_ConstDef.clear();
1591 		m_StrVarDef.clear();
1592 		ReInit();
1593 	}
1594 
1595 	//------------------------------------------------------------------------------
1596 	/** \brief Clear all user defined postfix operators.
1597 		\post Resets the parser to string parsing mode.
1598 		\throw nothrow
1599 	*/
ClearPostfixOprt()1600 	void ParserBase::ClearPostfixOprt()
1601 	{
1602 		m_PostOprtDef.clear();
1603 		ReInit();
1604 	}
1605 
1606 	//------------------------------------------------------------------------------
1607 	/** \brief Clear all user defined binary operators.
1608 		\post Resets the parser to string parsing mode.
1609 		\throw nothrow
1610 	*/
ClearOprt()1611 	void ParserBase::ClearOprt()
1612 	{
1613 		m_OprtDef.clear();
1614 		ReInit();
1615 	}
1616 
1617 	//------------------------------------------------------------------------------
1618 	/** \brief Clear the user defined Prefix operators.
1619 		\post Resets the parser to string parser mode.
1620 		\throw nothrow
1621 	*/
ClearInfixOprt()1622 	void ParserBase::ClearInfixOprt()
1623 	{
1624 		m_InfixOprtDef.clear();
1625 		ReInit();
1626 	}
1627 
1628 	//------------------------------------------------------------------------------
1629 	/** \brief Enable or disable the formula optimization feature.
1630 		\post Resets the parser to string parser mode.
1631 		\throw nothrow
1632 	*/
EnableOptimizer(bool a_bIsOn)1633 	void ParserBase::EnableOptimizer(bool a_bIsOn)
1634 	{
1635 		m_vRPN.EnableOptimizer(a_bIsOn);
1636 		ReInit();
1637 	}
1638 
1639 	//---------------------------------------------------------------------------
1640 	/** \brief Enable the dumping of bytecode and stack content on the console.
1641 		\param bDumpCmd Flag to enable dumping of the current bytecode to the console.
1642 		\param bDumpStack Flag to enable dumping of the stack content is written to the console.
1643 
1644 	   This function is for debug purposes only!
1645 	*/
EnableDebugDump(bool bDumpCmd,bool bDumpStack)1646 	void ParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack)
1647 	{
1648 		ParserBase::g_DbgDumpCmdCode = bDumpCmd;
1649 		ParserBase::g_DbgDumpStack = bDumpStack;
1650 	}
1651 
1652 	//------------------------------------------------------------------------------
1653 	/** \brief Enable or disable the built in binary operators.
1654 		\throw nothrow
1655 		\sa m_bBuiltInOp, ReInit()
1656 
1657 	  If you disable the built in binary operators there will be no binary operators
1658 	  defined. Thus you must add them manually one by one. It is not possible to
1659 	  disable built in operators selectively. This function will Reinitialize the
1660 	  parser by calling ReInit().
1661 	*/
EnableBuiltInOprt(bool a_bIsOn)1662 	void ParserBase::EnableBuiltInOprt(bool a_bIsOn)
1663 	{
1664 		m_bBuiltInOp = a_bIsOn;
1665 		ReInit();
1666 	}
1667 
1668 	//------------------------------------------------------------------------------
1669 	/** \brief Query status of built in variables.
1670 		\return #m_bBuiltInOp; true if built in operators are enabled.
1671 		\throw nothrow
1672 	*/
HasBuiltInOprt() const1673 	bool ParserBase::HasBuiltInOprt() const
1674 	{
1675 		return m_bBuiltInOp;
1676 	}
1677 
1678 	//------------------------------------------------------------------------------
1679 	/** \brief Get the argument separator character.
1680 	*/
GetArgSep() const1681 	char_type ParserBase::GetArgSep() const
1682 	{
1683 		return m_pTokenReader->GetArgSep();
1684 	}
1685 
1686 	//------------------------------------------------------------------------------
1687 	/** \brief Set argument separator.
1688 		\param cArgSep the argument separator character.
1689 	*/
SetArgSep(char_type cArgSep)1690 	void ParserBase::SetArgSep(char_type cArgSep)
1691 	{
1692 		m_pTokenReader->SetArgSep(cArgSep);
1693 	}
1694 
1695 	//------------------------------------------------------------------------------
1696 	/** \brief Dump stack content.
1697 
1698 		This function is used for debugging only.
1699 	*/
StackDump(const std::stack<token_type> & a_stVal,const std::stack<token_type> & a_stOprt) const1700 	void ParserBase::StackDump(const std::stack<token_type>& a_stVal, const std::stack<token_type>& a_stOprt) const
1701 	{
1702 		std::stack<token_type> stOprt(a_stOprt);
1703 		std::stack<token_type> stVal(a_stVal);
1704 
1705 		mu::console() << _T("\nValue stack:\n");
1706 		while (!stVal.empty())
1707 		{
1708 			token_type val = stVal.top();
1709 			stVal.pop();
1710 
1711 			if (val.GetType() == tpSTR)
1712 				mu::console() << _T(" \"") << val.GetAsString() << _T("\" ");
1713 			else
1714 				mu::console() << _T(" ") << val.GetVal() << _T(" ");
1715 		}
1716 		mu::console() << "\nOperator stack:\n";
1717 
1718 		while (!stOprt.empty())
1719 		{
1720 			if (stOprt.top().GetCode() <= cmASSIGN)
1721 			{
1722 				mu::console() << _T("OPRT_INTRNL \"")
1723 					<< ParserBase::c_DefaultOprt[stOprt.top().GetCode()]
1724 					<< _T("\" \n");
1725 			}
1726 			else
1727 			{
1728 				switch (stOprt.top().GetCode())
1729 				{
1730 				case cmVAR:   mu::console() << _T("VAR\n");  break;
1731 				case cmVAL:   mu::console() << _T("VAL\n");  break;
1732 				case cmFUNC:
1733 					mu::console()
1734 						<< _T("FUNC \"")
1735 						<< stOprt.top().GetAsString()
1736 						<< _T("\"\n");
1737 					break;
1738 
1739 				case cmFUNC_BULK:
1740 					mu::console()
1741 						<< _T("FUNC_BULK \"")
1742 						<< stOprt.top().GetAsString()
1743 						<< _T("\"\n");
1744 					break;
1745 
1746 				case cmOPRT_INFIX:
1747 					mu::console() << _T("OPRT_INFIX \"")
1748 						<< stOprt.top().GetAsString()
1749 						<< _T("\"\n");
1750 					break;
1751 
1752 				case cmOPRT_BIN:
1753 					mu::console() << _T("OPRT_BIN \"")
1754 						<< stOprt.top().GetAsString()
1755 						<< _T("\"\n");
1756 					break;
1757 
1758 				case cmFUNC_STR: mu::console() << _T("FUNC_STR\n");       break;
1759 				case cmEND:      mu::console() << _T("END\n");            break;
1760 				case cmUNKNOWN:  mu::console() << _T("UNKNOWN\n");        break;
1761 				case cmBO:       mu::console() << _T("BRACKET \"(\"\n");  break;
1762 				case cmBC:       mu::console() << _T("BRACKET \")\"\n");  break;
1763 				case cmIF:       mu::console() << _T("IF\n");  break;
1764 				case cmELSE:     mu::console() << _T("ELSE\n");  break;
1765 				case cmENDIF:    mu::console() << _T("ENDIF\n");  break;
1766 				default:         mu::console() << stOprt.top().GetCode() << _T(" ");  break;
1767 				}
1768 			}
1769 			stOprt.pop();
1770 		}
1771 
1772 		mu::console() << dec << endl;
1773 	}
1774 
1775 	/** \brief Calculate the result.
1776 
1777 	  A note on const correctness:
1778 	  I consider it important that Calc is a const function.
1779 	  Due to caching operations Calc changes only the state of internal variables with one exception
1780 	  m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making
1781 	  Calc non const GetUsedVar is non const because it explicitly calls Eval() forcing this update.
1782 
1783 	  \pre A formula must be set.
1784 	  \pre Variables must have been set (if needed)
1785 
1786 	  \sa #m_pParseFormula
1787 	  \return The evaluation result
1788 	  \throw ParseException if no Formula is set or in case of any other error related to the formula.
1789 	*/
Eval() const1790 	value_type ParserBase::Eval() const
1791 	{
1792 		return (this->*m_pParseFormula)();
1793 	}
1794 
1795 	//------------------------------------------------------------------------------
1796 	/** \brief Evaluate an expression containing comma separated subexpressions
1797 		\param [out] nStackSize The total number of results available
1798 		\return Pointer to the array containing all expression results
1799 
1800 		This member function can be used to retrieve all results of an expression
1801 		made up of multiple comma separated subexpressions (i.e. "x+y,sin(x),cos(y)")
1802 	*/
Eval(int & nStackSize) const1803 	value_type* ParserBase::Eval(int& nStackSize) const
1804 	{
1805 		if (m_vRPN.GetSize() > 0)
1806 		{
1807 			ParseCmdCode();
1808 		}
1809 		else
1810 		{
1811 			ParseString();
1812 		}
1813 
1814 		nStackSize = m_nFinalResultIdx;
1815 
1816 		// (for historic reasons the stack starts at position 1)
1817 		return &m_vStackBuffer[1];
1818 	}
1819 
1820 	//---------------------------------------------------------------------------
1821 	/** \brief Return the number of results on the calculation stack.
1822 
1823 	  If the expression contains comma separated subexpressions (i.e. "sin(y), x+y").
1824 	  There may be more than one return value. This function returns the number of
1825 	  available results.
1826 	*/
GetNumResults() const1827 	int ParserBase::GetNumResults() const
1828 	{
1829 		return m_nFinalResultIdx;
1830 	}
1831 
1832 	//---------------------------------------------------------------------------
Eval(value_type * results,int nBulkSize)1833 	void ParserBase::Eval(value_type* results, int nBulkSize)
1834 	{
1835 		CreateRPN();
1836 
1837 		int i = 0;
1838 
1839 #ifdef MUP_USE_OPENMP
1840 		//#define DEBUG_OMP_STUFF
1841 #ifdef DEBUG_OMP_STUFF
1842 		int* pThread = new int[nBulkSize];
1843 		int* pIdx = new int[nBulkSize];
1844 #endif
1845 
1846 		int nMaxThreads = std::min(omp_get_max_threads(), s_MaxNumOpenMPThreads);
1847 		int nThreadID = 0;
1848 
1849 #ifdef DEBUG_OMP_STUFF
1850 		int ct = 0;
1851 #endif
1852 		omp_set_num_threads(nMaxThreads);
1853 
1854 #pragma omp parallel for schedule(static, std::max(nBulkSize/nMaxThreads, 1)) private(nThreadID)
1855 		for (i = 0; i < nBulkSize; ++i)
1856 		{
1857 			nThreadID = omp_get_thread_num();
1858 			results[i] = ParseCmdCodeBulk(i, nThreadID);
1859 
1860 #ifdef DEBUG_OMP_STUFF
1861 #pragma omp critical
1862 			{
1863 				pThread[ct] = nThreadID;
1864 				pIdx[ct] = i;
1865 				ct++;
1866 			}
1867 #endif
1868 		}
1869 
1870 #ifdef DEBUG_OMP_STUFF
1871 		FILE* pFile = fopen("bulk_dbg.txt", "w");
1872 		for (i = 0; i < nBulkSize; ++i)
1873 		{
1874 			fprintf(pFile, "idx: %d  thread: %d \n", pIdx[i], pThread[i]);
1875 		}
1876 
1877 		delete[] pIdx;
1878 		delete[] pThread;
1879 
1880 		fclose(pFile);
1881 #endif
1882 
1883 #else
1884 		for (i = 0; i < nBulkSize; ++i)
1885 		{
1886 			results[i] = ParseCmdCodeBulk(i, 0);
1887 		}
1888 #endif
1889 
1890 	}
1891 } // namespace mu
1892 
1893 #if defined(_MSC_VER)
1894 	#pragma warning(pop)
1895 #endif
1896 
1897