Add HeFFTe based FFT backend
[alexxy/gromacs.git] / src / external / muparser / muParserBase.cpp
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         */
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         */
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         //---------------------------------------------------------------------------
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         */
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         */
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         */
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         */
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         */
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         */
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         */
254         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         //---------------------------------------------------------------------------
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         */
274         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         */
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         */
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. */
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         */
368         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         */
390         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         */
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         */
432         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         */
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         */
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         */
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         */
468         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         */
478         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         */
488         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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
628         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         */
664         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. */
689         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. */
713         const varmap_type& ParserBase::GetVar() const
714         {
715                 return m_VarDef;
716         }
717
718         //---------------------------------------------------------------------------
719         /** \brief Return a map containing all parser constants. */
720         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         */
736         const funmap_type& ParserBase::GetFunDef() const
737         {
738                 return m_FunDef;
739         }
740
741         //---------------------------------------------------------------------------
742         /** \brief Retrieve the formula. */
743         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         */
753         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         */
795         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         //---------------------------------------------------------------------------
885         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         */
927         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         */
974         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         */
1023         value_type ParserBase::ParseCmdCode() const
1024         {
1025                 return ParseCmdCodeBulk(0, 0);
1026         }
1027
1028         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         */
1074         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         //---------------------------------------------------------------------------
1243         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         */
1502         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         */
1537         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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
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         */
1673         bool ParserBase::HasBuiltInOprt() const
1674         {
1675                 return m_bBuiltInOp;
1676         }
1677
1678         //------------------------------------------------------------------------------
1679         /** \brief Get the argument separator character.
1680         */
1681         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         */
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         */
1700         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         */
1790         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         */
1803         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         */
1827         int ParserBase::GetNumResults() const
1828         {
1829                 return m_nFinalResultIdx;
1830         }
1831
1832         //---------------------------------------------------------------------------
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