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