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