Seamly2D
Code documentation
qmuparserbase.cpp
Go to the documentation of this file.
1 /***************************************************************************************************
2  **
3  ** Copyright (C) 2013 Ingo Berg
4  **
5  ** Permission is hereby granted, free of charge, to any person obtaining a copy of this
6  ** software and associated documentation files (the "Software"), to deal in the Software
7  ** without restriction, including without limitation the rights to use, copy, modify,
8  ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9  ** permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  **
11  ** The above copyright notice and this permission notice shall be included in all copies or
12  ** substantial portions of the Software.
13  **
14  ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
15  ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16  ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17  ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  **
20  ******************************************************************************************************/
21 
22 #include "qmuparserbase.h"
23 
24 #include <QList>
25 #include <QMessageLogger>
26 #include <QStack>
27 #include <QStringList>
28 #include <QTextStream>
29 #include <QtDebug>
30 #include <map>
31 #ifdef QMUP_USE_OPENMP
32  #include <omp.h>
33 #endif
34 #include <assert.h>
35 
36 #include "qmudef.h"
37 #include "../vmisc/vmath.h"
38 
39 /**
40  * @file
41  * @brief This file contains the basic implementation of the muparser engine.
42  */
43 
44 namespace qmu
45 {
46 
49 
50 /**
51  * @brief Identifiers for built in binary operators.
52  *
53  * When defining custom binary operators with #AddOprt(...) make sure not to choose
54  * names conflicting with these definitions.
55  */
56 const QStringList QmuParserBase::c_DefaultOprt = QStringList()<< "<=" << ">=" << "!=" << "==" << "<" << ">" << "+"
57  << "-" << "*" << "/" << "^" << "&&" << "||" << "="
58  << "(" << ")" << "?" << ":";
59 
60 //---------------------------------------------------------------------------------------------------------------------
61 /**
62  * @brief Constructor.
63  */
65  : m_locale(QLocale::c()),
66  m_decimalPoint(QLocale::c().decimalPoint()),
67  m_thousandsSeparator(QLocale::c().groupSeparator()),
68  m_pParseFormula(&QmuParserBase::ParseString),
69  m_vRPN(),
70  m_vStringBuf(),
71  m_vStringVarBuf(),
72  m_pTokenReader(),
73  m_FunDef(),
74  m_PostOprtDef(),
75  m_InfixOprtDef(),
76  m_OprtDef(),
77  m_ConstDef(),
78  m_StrVarDef(),
79  m_VarDef(),
80  m_bBuiltInOp(true),
81  m_sNameChars(),
82  m_sOprtChars(),
83  m_sInfixOprtChars(),
84  m_nIfElseCounter(0),
85  m_vStackBuffer(),
86  m_nFinalResultIdx(0),
87  m_Tokens(QMap<int, QString>()),
88  m_Numbers(QMap<int, QString>()),
89  allowSubexpressions(true)
90 {
92 }
93 
94 //---------------------------------------------------------------------------------------------------------------------
95 /**
96  * @brief Copy constructor.
97  *
98  * Tha parser can be safely copy constructed but the bytecode is reset during copy construction.
99  */
101  : m_locale(a_Parser.getLocale()),
102  m_decimalPoint(a_Parser.getDecimalPoint()),
103  m_thousandsSeparator(a_Parser.getThousandsSeparator()),
104  m_pParseFormula(&QmuParserBase::ParseString),
105  m_vRPN(),
106  m_vStringBuf(),
107  m_vStringVarBuf(),
108  m_pTokenReader(),
109  m_FunDef(),
110  m_PostOprtDef(),
111  m_InfixOprtDef(),
112  m_OprtDef(),
113  m_ConstDef(),
114  m_StrVarDef(),
115  m_VarDef(),
116  m_bBuiltInOp(true),
117  m_sNameChars(),
118  m_sOprtChars(),
119  m_sInfixOprtChars(),
120  m_nIfElseCounter(0),
121  m_vStackBuffer(),
122  m_nFinalResultIdx(0),
123  m_Tokens(QMap<int, QString>()),
124  m_Numbers(QMap<int, QString>()),
125  allowSubexpressions(true)
126 {
127  m_pTokenReader.reset(new token_reader_type(this));
128  Assign(a_Parser);
129 }
130 
131 //---------------------------------------------------------------------------------------------------------------------
133 {}
134 
135 //---------------------------------------------------------------------------------------------------------------------
136 /**
137  * @brief Assignement operator.
138  *
139  * Implemented by calling Assign(a_Parser). Self assignement is suppressed.
140  * @param a_Parser Object to copy to this.
141  * @return *this
142  * @throw nothrow
143  */
145 {
146  if (this != &a_Parser)
147  {
148  Assign(a_Parser);
149  }
150  return *this;
151 }
152 
153 //---------------------------------------------------------------------------------------------------------------------
154 /**
155  * @brief Copy state of a parser object to this.
156  *
157  * Clears Variables and Functions of this parser.
158  * Copies the states of all internal variables.
159  * Resets parse function to string parse mode.
160  *
161  * @param a_Parser the source object.
162  */
164 {
165  if (&a_Parser==this)
166  {
167  return;
168  }
169 
170  // Don't copy bytecode instead cause the parser to create new bytecode
171  // by resetting the parse function.
172  ReInit();
173 
174  m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants
175  m_VarDef = a_Parser.m_VarDef; // Copy user defined variables
176  m_bBuiltInOp = a_Parser.m_bBuiltInOp;
177  m_vStringBuf = a_Parser.m_vStringBuf;
178  m_vStackBuffer = a_Parser.m_vStackBuffer;
180  m_StrVarDef = a_Parser.m_StrVarDef;
181  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;
194 }
195 
196 //---------------------------------------------------------------------------------------------------------------------
197 /**
198  * @brief Resets the locale.
199  *
200  * The default locale used "." as decimal separator, no thousands separator and "," as function argument separator.
201  */
202 // cppcheck-suppress unusedFunction
204 {
205  setLocale(QLocale::c());
206  m_decimalPoint = m_locale.decimalPoint();
207  m_thousandsSeparator = m_locale.groupSeparator();
208  SetArgSep(';');
209 }
210 
211 //---------------------------------------------------------------------------------------------------------------------
212 /**
213  * @brief Reset parser to string parsing mode and clear internal buffers.
214  *
215  * Clear bytecode, reset the token reader.
216  * @throw nothrow
217  */
219 {
221  m_vStringBuf.clear();
222  m_vRPN.clear();
223  m_pTokenReader->ReInit();
224  m_nIfElseCounter = 0;
225  m_Tokens.clear();
226  m_Numbers.clear();
227 }
228 
229 //---------------------------------------------------------------------------------------------------------------------
230 void QmuParserBase::OnDetectVar(const QString &pExpr, int &nStart, int &nEnd)
231 {
232  Q_UNUSED(pExpr)
233  Q_UNUSED(nStart)
234  Q_UNUSED(nEnd)
235 }
236 
237 //---------------------------------------------------------------------------------------------------------------------
239 {
240  allowSubexpressions = value;
241 }
242 
243 //---------------------------------------------------------------------------------------------------------------------
245 {
246  return m_locale;
247 }
248 
249 //---------------------------------------------------------------------------------------------------------------------
250 void QmuParserBase::setLocale(const QLocale &value)
251 {
252  m_locale = value;
253  InitCharSets();
254  InitOprt();
255 }
256 
257 //---------------------------------------------------------------------------------------------------------------------
259 {
260  return m_decimalPoint;
261 }
262 
263 //---------------------------------------------------------------------------------------------------------------------
264 void QmuParserBase::setDecimalPoint(const QChar &c)
265 {
266  m_decimalPoint = c;
267 }
268 
269 //---------------------------------------------------------------------------------------------------------------------
271 {
272  return m_thousandsSeparator;
273 }
274 
275 //---------------------------------------------------------------------------------------------------------------------
277 {
279 }
280 
281 //---------------------------------------------------------------------------------------------------------------------
282 /**
283  * @brief Returns the version of muparser.
284  * @param eInfo A flag indicating whether the full version info should be returned or not.
285  *
286  * Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS are returned only if eInfo==pviFULL.
287  */
288 // cppcheck-suppress unusedFunction
290 {
291  QString versionInfo;
292  QTextStream ss(&versionInfo);
293 
294  ss << QMUP_VERSION;
295 
296  if (eInfo==pviFULL)
297  {
298  ss << " (" << QMUP_VERSION_DATE;
299  ss << "; " << sizeof(void*)*8 << "BIT";
300 
301  #ifdef _DEBUG
302  ss << "; DEBUG";
303  #else
304  ss << "; RELEASE";
305  #endif
306 
307  #ifdef _UNICODE
308  ss << "; UNICODE";
309  #else
310  #ifdef _MBCS
311  ss << "; MBCS";
312  #else
313  ss << "; ASCII";
314  #endif
315  #endif
316 
317  #ifdef QMUP_USE_OPENMP
318  ss << "; OPENMP";
319  //#else
320  // ss << "; NO_OPENMP";
321  #endif
322 
323  #if defined(MUP_MATH_EXCEPTIONS)
324  ss << "; MATHEXC";
325  //#else
326  // ss << "; NO_MATHEXC";
327  #endif
328 
329  ss << ")";
330  }
331  return versionInfo;
332 }
333 
334 //---------------------------------------------------------------------------------------------------------------------
335 /**
336  * @brief Add a function or operator callback to the parser.
337  */
338 void QmuParserBase::AddCallback(const QString &a_strName, const QmuParserCallback &a_Callback,
339  funmap_type &a_Storage, const QString &a_szCharSet )
340 {
341  if (a_Callback.GetAddr() == nullptr)
342  {
344  }
345 
346  const funmap_type *pFunMap = &a_Storage;
347 
348  // Check for conflicting operator or function names
349  if ( pFunMap!=&m_FunDef && m_FunDef.find(a_strName)!=m_FunDef.end() )
350  {
351  Error(ecNAME_CONFLICT, -1, a_strName);
352  }
353 
354  if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() )
355  {
356  Error(ecNAME_CONFLICT, -1, a_strName);
357  }
358 
359  if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() )
360  {
361  Error(ecNAME_CONFLICT, -1, a_strName);
362  }
363 
364  if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() )
365  {
366  Error(ecNAME_CONFLICT, -1, a_strName);
367  }
368 
369  CheckOprt(a_strName, a_Callback, a_szCharSet);
370  a_Storage[a_strName] = a_Callback;
371  ReInit();
372 }
373 
374 //---------------------------------------------------------------------------------------------------------------------
375 /**
376  * @brief Check if a name contains invalid characters.
377  *
378  * @throw ParserException if the name contains invalid charakters.
379  */
380 // cppcheck-suppress
381 void QmuParserBase::CheckOprt(const QString &a_sName, const QmuParserCallback &a_Callback,
382  const QString &a_szCharSet) const
383 {
384  const std::wstring a_sNameStd = a_sName.toStdWString();
385  const std::wstring a_szCharSetStd = a_szCharSet.toStdWString();
386 
387  if ( a_sNameStd.length() == false || (a_sNameStd.find_first_not_of(a_szCharSetStd)!=string_type::npos) ||
388  (a_sNameStd.at(0)>='0' && a_sNameStd.at(0)<='9'))
389  {
390  switch (a_Callback.GetCode())
391  {
392  case cmOPRT_POSTFIX:
393  Error(ecINVALID_POSTFIX_IDENT, -1, a_sName);
394  break;
395  case cmOPRT_INFIX:
396  Error(ecINVALID_INFIX_IDENT, -1, a_sName);
397  break;
398  default:
399  Error(ecINVALID_NAME, -1, a_sName);
400  break;
401  }
402  }
403 }
404 
405 //---------------------------------------------------------------------------------------------------------------------
406 /**
407  * @brief Check if a name contains invalid characters.
408  *
409  * @throw ParserException if the name contains invalid characters.
410  */
411 void QmuParserBase::CheckName(const QString &a_sName, const QString &a_szCharSet) const
412 {
413  std::wstring a_sNameStd = a_sName.toStdWString();
414  std::wstring a_szCharSetStd = a_szCharSet.toStdWString();
415 
416  if ( a_sNameStd.length() == false || (a_sNameStd.find_first_not_of(a_szCharSetStd)!=string_type::npos) ||
417  (a_sNameStd[0]>='0' && a_sNameStd[0]<='9'))
418  {
420  }
421 }
422 
423 //---------------------------------------------------------------------------------------------------------------------
424 /**
425  * @brief Set the formula.
426  * @param a_sExpr Formula as string_type
427  * @throw ParserException in case of syntax errors.
428  *
429  * Triggers first time calculation thus the creation of the bytecode and scanning of used variables.
430  */
431 void QmuParserBase::SetExpr(const QString &a_sExpr)
432 {
433  // Check locale compatibility
434  std::locale loc;
435  if (m_pTokenReader->GetArgSep()==std::use_facet<std::numpunct<char_type> >(loc).decimal_point())
436  {
437  Error(ecLOCALE);
438  }
439 
440  // <ibg> 20060222: Bugfix for Borland-Kylix:
441  // adding a space to the expression will keep Borlands KYLIX from going wild
442  // when calling tellg on a stringstream created from the expression after
443  // reading a value at the end of an expression. (qmu::QmuParser::IsVal function)
444  // (tellg returns -1 otherwise causing the parser to ignore the value)
445  QString sBuf(a_sExpr + " " );
446  m_pTokenReader->SetFormula(sBuf);
447  ReInit();
448 }
449 
450 //---------------------------------------------------------------------------------------------------------------------
451 /**
452  * @brief Virtual function that defines the characters allowed in name identifiers.
453  * @sa #ValidOprtChars, #ValidPrefixOprtChars
454  */
455 const QString& QmuParserBase::ValidNameChars() const
456 {
457  assert(m_sNameChars.size());
458  return m_sNameChars;
459 }
460 
461 //---------------------------------------------------------------------------------------------------------------------
462 /**
463  * @brief Virtual function that defines the characters allowed in operator definitions.
464  * @sa #ValidNameChars, #ValidPrefixOprtChars
465  */
466 const QString &QmuParserBase::ValidOprtChars() const
467 {
468  assert(m_sOprtChars.size());
469  return m_sOprtChars;
470 }
471 
472 //---------------------------------------------------------------------------------------------------------------------
473 /**
474  * @brief Virtual function that defines the characters allowed in infix operator definitions.
475  * @sa #ValidNameChars, #ValidOprtChars
476  */
478 {
479  assert(m_sInfixOprtChars.size());
480  return m_sInfixOprtChars;
481 }
482 
483 //---------------------------------------------------------------------------------------------------------------------
484 /**
485  * @brief Add a user defined operator.
486  * @post Will reset the Parser to string parsing mode.
487  */
488 void QmuParserBase::DefinePostfixOprt(const QString &a_sFun, fun_type1 a_pFun, bool a_bAllowOpt)
489 {
490  AddCallback(a_sFun, QmuParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), m_PostOprtDef,
491  ValidOprtChars() );
492 }
493 
494 //---------------------------------------------------------------------------------------------------------------------
495 /**
496  * @brief Initialize user defined functions.
497  *
498  * Calls the virtual functions InitFun(), InitConst() and InitOprt().
499  */
500 // cppcheck-suppress unusedFunction
502 {
503  InitCharSets();
504  InitFun();
505  InitConst();
506  InitOprt();
507 }
508 
509 //---------------------------------------------------------------------------------------------------------------------
510 /**
511  * @brief Add a user defined operator.
512  * @post Will reset the Parser to string parsing mode.
513  * @param [in] a_sName operator Identifier
514  * @param [in] a_pFun Operator callback function
515  * @param [in] a_iPrec Operator Precedence (default=prSIGN)
516  * @param [in] a_bAllowOpt True if operator is volatile (default=false)
517  * @sa EPrec
518  */
519 void QmuParserBase::DefineInfixOprt(const QString &a_sName, fun_type1 a_pFun, int a_iPrec, bool a_bAllowOpt)
520 {
521  AddCallback(a_sName, QmuParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), m_InfixOprtDef,
523 }
524 
525 //---------------------------------------------------------------------------------------------------------------------
526 /**
527  * @brief Define a binary operator.
528  * @param [in] a_sName The identifier of the operator.
529  * @param [in] a_pFun Pointer to the callback function.
530  * @param [in] a_iPrec Precedence of the operator.
531  * @param [in] a_eAssociativity The associativity of the operator.
532  * @param [in] a_bAllowOpt If this is true the operator may be optimized away.
533  *
534  * Adds a new Binary operator the the parser instance.
535  */
536 void QmuParserBase::DefineOprt( const QString &a_sName, fun_type2 a_pFun, unsigned a_iPrec,
537  EOprtAssociativity a_eAssociativity, bool a_bAllowOpt )
538 {
539  // Check for conflicts with built in operator names
540  for (int i=0; m_bBuiltInOp && i<cmENDIF; ++i)
541  {
542  if (a_sName == c_DefaultOprt.at(i))
543  {
544  Error(ecBUILTIN_OVERLOAD, -1, a_sName);
545  }
546  }
547 
548  AddCallback(a_sName, QmuParserCallback(a_pFun, a_bAllowOpt, static_cast<int>(a_iPrec), a_eAssociativity), m_OprtDef,
549  ValidOprtChars() );
550 }
551 
552 //---------------------------------------------------------------------------------------------------------------------
553 /**
554  * @brief Define a new string constant.
555  * @param [in] a_strName The name of the constant.
556  * @param [in] a_strVal the value of the constant.
557  */
558 // cppcheck-suppress unusedFunction
559 void QmuParserBase::DefineStrConst(const QString &a_strName, const QString &a_strVal)
560 {
561  // Test if a constant with that names already exists
562  if (m_StrVarDef.find(a_strName)!=m_StrVarDef.end())
563  {
565  }
566 
567  CheckName(a_strName, ValidNameChars());
568 
569  m_vStringVarBuf.push_back(a_strVal); // Store variable string in internal buffer
570  m_StrVarDef[a_strName] = m_vStringBuf.size(); // bind buffer index to variable name
571 
572  ReInit();
573 }
574 
575 //---------------------------------------------------------------------------------------------------------------------
576 /**
577  * @brief Add a user defined variable.
578  * @param [in] a_sName the variable name
579  * @param [in] a_pVar A pointer to the variable vaule.
580  * @post Will reset the Parser to string parsing mode.
581  * @throw ParserException in case the name contains invalid signs or a_pVar is NULL.
582  */
583 void QmuParserBase::DefineVar(const QString &a_sName, qreal *a_pVar)
584 {
585  if (a_pVar == nullptr)
586  {
588  }
589 
590  // Test if a constant with that names already exists
591  if (m_ConstDef.find(a_sName)!=m_ConstDef.end())
592  {
594  }
595 
596  CheckName(a_sName, ValidNameChars());
597  m_VarDef[a_sName] = a_pVar;
598  ReInit();
599 }
600 
601 //---------------------------------------------------------------------------------------------------------------------
602 /**
603  * @brief Add a user defined constant.
604  * @param [in] a_sName The name of the constant.
605  * @param [in] a_fVal the value of the constant.
606  * @post Will reset the Parser to string parsing mode.
607  * @throw ParserException in case the name contains invalid signs.
608  */
609 void QmuParserBase::DefineConst(const QString &a_sName, qreal a_fVal)
610 {
611  CheckName(a_sName, ValidNameChars());
612  m_ConstDef[a_sName] = a_fVal;
613  ReInit();
614 }
615 
616 //---------------------------------------------------------------------------------------------------------------------
617 /**
618  * @brief Get operator priority.
619  * @throw ParserException if a_Oprt is no operator code
620  */
622 {
623  switch (a_Tok.GetCode())
624  {
625  // built in operators
626  case cmEND:
627  return -5;
628  case cmARG_SEP:
629  return -4;
630  case cmASSIGN:
631  return -1;
632  case cmELSE:
633  case cmIF:
634  return 0;
635  case cmLAND:
636  return prLAND;
637  case cmLOR:
638  return prLOR;
639  case cmLT:
640  case cmGT:
641  case cmLE:
642  case cmGE:
643  case cmNEQ:
644  case cmEQ:
645  return prCMP;
646  case cmADD:
647  case cmSUB:
648  return prADD_SUB;
649  case cmMUL:
650  case cmDIV:
651  return prMUL_DIV;
652  case cmPOW:
653  return prPOW;
654  // user defined binary operators
655  case cmOPRT_INFIX:
656  case cmOPRT_BIN:
657  return a_Tok.GetPri();
658  default:
660  return 999;
661  }
662 }
663 
664 //---------------------------------------------------------------------------------------------------------------------
665 /**
666  * @brief Get operator priority.
667  * @throw ParserException if a_Oprt is no operator code
668  */
670 {
671  switch (a_Tok.GetCode())
672  {
673  case cmASSIGN:
674  case cmLAND:
675  case cmLOR:
676  case cmLT:
677  case cmGT:
678  case cmLE:
679  case cmGE:
680  case cmNEQ:
681  case cmEQ:
682  case cmADD:
683  case cmSUB:
684  case cmMUL:
685  case cmDIV:
686  return oaLEFT;
687  case cmPOW:
688  return oaRIGHT;
689  case cmOPRT_BIN:
690  return a_Tok.GetAssociativity();
691  default:
692  return oaNONE;
693  }
694 }
695 
696 //---------------------------------------------------------------------------------------------------------------------
697 /**
698  * @brief Return a map containing the used variables only.
699  */
701 {
702  try
703  {
704  m_pTokenReader->IgnoreUndefVar(true);
705  CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it
706  // may contain references to nonexisting variables.
708  m_pTokenReader->IgnoreUndefVar(false);
709  }
710  catch (const QmuParserError &e)
711  {
712  Q_UNUSED(e)
713  // Make sure to stay in string parse mode, dont call ReInit()
714  // because it deletes the array with the used variables
716  m_pTokenReader->IgnoreUndefVar(false);
717  throw;
718  }
719  return m_pTokenReader->GetUsedVar();
720 }
721 
722 //---------------------------------------------------------------------------------------------------------------------
723 /**
724  * @brief Execute a function that takes a single string argument.
725  * @param a_FunTok Function token.
726  * @throw QmuParserError If the function token is not a string function
727  */
729  const QVector<token_type> &a_vArg) const
730 {
731  if (a_vArg.back().GetCode()!=cmSTRING)
732  {
733  Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
734  }
735 
736  token_type valTok;
737  generic_fun_type pFunc = a_FunTok.GetFuncAddr();
738  assert(pFunc);
739 
740  try
741  {
742  // Check function arguments; write dummy value into valtok to represent the result
743  switch (a_FunTok.GetArgCount())
744  {
745  case 0:
746  valTok.SetVal(1);
747  a_vArg[0].GetAsString();
748  break;
749  case 1:
750  valTok.SetVal(1);
751  a_vArg[1].GetAsString();
752  a_vArg[0].GetVal();
753  break;
754  case 2:
755  valTok.SetVal(1);
756  a_vArg[2].GetAsString();
757  a_vArg[1].GetVal();
758  a_vArg[0].GetVal();
759  break;
760  default:
762  break;
763  }
764  }
765  catch (QmuParserError& )
766  {
767  Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
768  }
769 
770  // string functions won't be optimized
771  m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx());
772 
773  // Push dummy value representing the function result to the stack
774  return valTok;
775 }
776 
777 //---------------------------------------------------------------------------------------------------------------------
778 /**
779  * @brief Apply a function token.
780  * @param a_iArgCount Number of Arguments actually gathered used only for multiarg functions.
781  * @post The result is pushed to the value stack
782  * @post The function token is removed from the stack
783  * @throw QmuParserError if Argument count does not mach function requirements.
784  */
785 void QmuParserBase::ApplyFunc( QStack<token_type> &a_stOpt, QStack<token_type> &a_stVal, int a_iArgCount) const
786 {
787  assert(m_pTokenReader.get());
788 
789  // Operator stack empty or does not contain tokens with callback functions
790  if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr() == nullptr)
791  {
792  return;
793  }
794 
795  token_type funTok = a_stOpt.pop();
796  assert(funTok.GetFuncAddr());
797 
798  // Binary operators must rely on their internal operator number
799  // since counting of operators relies on commas for function arguments
800  // binary operators do not have commas in their expression
801  int iArgCount = (funTok.GetCode()==cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount;
802 
803  // determine how many parameters the function needs. To remember iArgCount includes the
804  // string parameter whilst GetArgCount() counts only numeric parameters.
805  int iArgRequired = funTok.GetArgCount() + ((funTok.GetType()==tpSTR) ? 1 : 0);
806 
807  // Thats the number of numerical parameters
808  int iArgNumerical = iArgCount - ((funTok.GetType()==tpSTR) ? 1 : 0);
809 
810  if (funTok.GetCode()==cmFUNC_STR && iArgCount-iArgNumerical>1)
811  {
813  }
814 
815  if (funTok.GetArgCount()>=0 && iArgCount>iArgRequired)
816  {
817  Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());
818  }
819 
820  if (funTok.GetCode()!=cmOPRT_BIN && iArgCount<iArgRequired )
821  {
822  Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());
823  }
824 
825  if (funTok.GetCode()==cmFUNC_STR && iArgCount>iArgRequired )
826  {
827  Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());
828  }
829 
830  // Collect the numeric function arguments from the value stack and store them
831  // in a vector
832  QVector<token_type> stArg;
833  for (int i=0; i<iArgNumerical; ++i)
834  {
835  if (a_stVal.isEmpty())// Check if stack is empty like in origin muparser.
836  {
838  }
839  stArg.push_back( a_stVal.pop() );
840  if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR )
841  {
842  Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
843  }
844  }
845 
846  switch (funTok.GetCode())
847  {
848  case cmFUNC_STR:
849  stArg.push_back(a_stVal.pop());
850 
851  if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR )
852  {
853  Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
854  }
855 
856  ApplyStrFunc(funTok, stArg);
857  break;
858  case cmFUNC_BULK:
859  m_vRPN.AddBulkFun(funTok.GetFuncAddr(), stArg.size());
860  break;
861  case cmOPRT_BIN:
862  case cmOPRT_POSTFIX:
863  case cmOPRT_INFIX:
864  case cmFUNC:
865  if (funTok.GetArgCount()==-1 && iArgCount==0)
866  {
867  Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString());
868  }
869 
870  m_vRPN.AddFun(funTok.GetFuncAddr(), (funTok.GetArgCount()==-1) ? -iArgNumerical : iArgNumerical);
871  break;
872  default:
873  break;
874  }
875  // Push dummy value representing the function result to the stack
876  token_type token;
877  token.SetVal(1);
878  a_stVal.push(token);
879 }
880 
881 //---------------------------------------------------------------------------------------------------------------------
883 {
884  // Check if there is an if Else clause to be calculated
885  while (a_stOpt.size() && a_stOpt.top().GetCode()==cmELSE)
886  {
887  token_type opElse = a_stOpt.pop();
888  Q_ASSERT(a_stOpt.size()>0);
889 
890  // Take the value associated with the else branch from the value stack
891  token_type vVal2 = a_stVal.pop();
892 
893  Q_ASSERT(a_stOpt.size()>0);
894  Q_ASSERT(a_stVal.size()>=2);
895 
896  // it then else is a ternary operator Pop all three values from the value s
897  // tack and just return the right value
898  token_type vVal1 = a_stVal.pop();
899  token_type vExpr = a_stVal.pop();
900 
901  a_stVal.push( not qFuzzyIsNull(vExpr.GetVal()) ? vVal1 : vVal2);
902 
903  token_type opIf = a_stOpt.pop();
904  Q_ASSERT(opElse.GetCode()==cmELSE);
905  Q_ASSERT(opIf.GetCode()==cmIF);
906 
908  } // while pending if-else-clause found
909 }
910 
911 //---------------------------------------------------------------------------------------------------------------------
912 /**
913  * @brief Performs the necessary steps to write code for the execution of binary operators into the bytecode.
914  */
916 {
917  // is it a user defined binary operator?
918  if (a_stOpt.top().GetCode()==cmOPRT_BIN)
919  {
920  ApplyFunc(a_stOpt, a_stVal, 2);
921  }
922  else
923  {
924  if(a_stVal.size()<2)
925  {
927  }
928 
929  token_type valTok1 = a_stVal.pop(),
930  valTok2 = a_stVal.pop(),
931  optTok = a_stOpt.pop(),
932  resTok;
933 
934  if ( valTok1.GetType()!=valTok2.GetType() || (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) )
935  {
936  Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString());
937  }
938 
939  if (optTok.GetCode()==cmASSIGN)
940  {
941  if (valTok2.GetCode()!=cmVAR)
942  {
943  Error(ecUNEXPECTED_OPERATOR, -1, "=");
944  }
945  m_vRPN.AddAssignOp(valTok2.GetVar());
946  }
947  else
948  {
949  m_vRPN.AddOp(optTok.GetCode());
950  }
951  resTok.SetVal(1);
952  a_stVal.push(resTok);
953  }
954 }
955 
956 //---------------------------------------------------------------------------------------------------------------------
957 /**
958  * @brief Apply a binary operator.
959  * @param stOpt The operator stack
960  * @param stVal The value stack
961  */
963 {
964  while (stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmIF)
965  {
966  const ECmdCode code = stOpt.top().GetCode();
967 
968  if ((code >= cmLE && code <= cmASSIGN) || code == cmOPRT_INFIX || code == cmOPRT_BIN)
969  {
970  if (code==cmOPRT_INFIX)
971  {
972  ApplyFunc(stOpt, stVal, 1);
973  }
974  else
975  {
976  ApplyBinOprt(stOpt, stVal);
977  }
978  }
979  else if (code == cmELSE)
980  {
981  ApplyIfElse(stOpt, stVal);
982  }
983  else
984  {
986  }
987  }
988 }
989 
990 //---------------------------------------------------------------------------------------------------------------------
991 /**
992  * @brief Parse the command code.
993  * @sa ParseString(...)
994  *
995  * Command code contains precalculated stack positions of the values and the associated operators. The Stack is
996  * filled beginning from index one the value at index zero is not used at all.
997  */
999 {
1000  return ParseCmdCodeBulk(0, 0);
1001 }
1002 
1003 //---------------------------------------------------------------------------------------------------------------------
1004 /**
1005  * @brief Evaluate the RPN.
1006  * @param nOffset The offset added to variable addresses (for bulk mode)
1007  * @param nThreadID OpenMP Thread id of the calling thread
1008  */
1009 qreal QmuParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const
1010 {
1011  assert(nThreadID<=s_MaxNumOpenMPThreads);
1012 
1013  // Note: The check for nOffset==0 and nThreadID here is not necessary but
1014  // brings a minor performance gain when not in bulk mode.
1015  qreal *Stack = ((nOffset==0) && (nThreadID==0)) ? &m_vStackBuffer[0] : &m_vStackBuffer[nThreadID *
1017  qreal buf;
1018  int sidx(0);
1019  for (const SToken *pTok = m_vRPN.GetBase(); pTok->Cmd!=cmEND ; ++pTok)
1020  {
1021  switch (pTok->Cmd)
1022  {
1023  // built in binary operators
1024  case cmLE:
1025  --sidx;
1026  Stack[sidx] = Stack[sidx] <= Stack[sidx+1];
1027  continue;
1028  case cmGE:
1029  --sidx;
1030  Stack[sidx] = Stack[sidx] >= Stack[sidx+1];
1031  continue;
1032  case cmNEQ:
1033  --sidx;
1034  Stack[sidx] = not QmuFuzzyComparePossibleNulls(Stack[sidx], Stack[sidx+1]);
1035  continue;
1036  case cmEQ:
1037  --sidx;
1038  Stack[sidx] = QmuFuzzyComparePossibleNulls(Stack[sidx], Stack[sidx+1]);
1039  continue;
1040  case cmLT:
1041  --sidx;
1042  Stack[sidx] = Stack[sidx] < Stack[sidx+1];
1043  continue;
1044  case cmGT:
1045  --sidx;
1046  Stack[sidx] = Stack[sidx] > Stack[sidx+1];
1047  continue;
1048  case cmADD:
1049  --sidx;
1050  Stack[sidx] += Stack[1+sidx];
1051  continue;
1052  case cmSUB:
1053  --sidx;
1054  Stack[sidx] -= Stack[1+sidx];
1055  continue;
1056  case cmMUL:
1057  --sidx;
1058  Stack[sidx] *= Stack[1+sidx];
1059  continue;
1060  case cmDIV:
1061  --sidx;
1062  #if defined(MUP_MATH_EXCEPTIONS)
1063  if (Stack[1+sidx]==0)
1064  {
1066  }
1067  #endif
1068  Stack[sidx] /= Stack[1+sidx];
1069  continue;
1070  case cmPOW:
1071  --sidx;
1072  Stack[sidx] = qPow(Stack[sidx], Stack[1+sidx]);
1073  continue;
1074  case cmLAND:
1075  --sidx;
1076 QT_WARNING_PUSH
1077 QT_WARNING_DISABLE_GCC("-Wfloat-equal")
1078  Stack[sidx] = static_cast<bool>(Stack[sidx]) && static_cast<bool>(Stack[sidx+1]);
1080  continue;
1081  case cmLOR:
1082  --sidx;
1083 QT_WARNING_PUSH
1084 QT_WARNING_DISABLE_GCC("-Wfloat-equal")
1085  Stack[sidx] = static_cast<bool>(Stack[sidx]) || static_cast<bool>(Stack[sidx+1]);
1087  continue;
1088  case cmASSIGN:
1089  // Bugfix for Bulkmode:
1090  // for details see:
1091  // https://groups.google.com/forum/embed/?place=forum/muparser-dev&showsearch=true&showpopout=true&
1092  // showtabs=false&parenturl=http://muparser.beltoforion.de/mup_forum.html&afterlogin&pli=1#!topic/
1093  // muparser-dev/szgatgoHTws
1094  --sidx;
1095  Stack[sidx] = *(pTok->Oprt.ptr + nOffset) = Stack[sidx + 1];
1096  continue;
1097  // original code:
1098  //--sidx;
1099  //Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1];
1100  //continue;
1101  case cmIF:
1102  if (qFuzzyIsNull(Stack[sidx--]))
1103  {
1104  pTok += pTok->Oprt.offset;
1105  }
1106  continue;
1107  case cmELSE:
1108  pTok += pTok->Oprt.offset;
1109  continue;
1110  case cmENDIF:
1111  continue;
1112 
1113  // value and variable tokens
1114  case cmVAR:
1115  Stack[++sidx] = *(pTok->Val.ptr + nOffset);
1116  continue;
1117  case cmVAL:
1118  Stack[++sidx] = pTok->Val.data2;
1119  continue;
1120  case cmVARPOW2:
1121  buf = *(pTok->Val.ptr + nOffset);
1122  Stack[++sidx] = buf*buf;
1123  continue;
1124  case cmVARPOW3:
1125  buf = *(pTok->Val.ptr + nOffset);
1126  Stack[++sidx] = buf*buf*buf;
1127  continue;
1128  case cmVARPOW4:
1129  buf = *(pTok->Val.ptr + nOffset);
1130  Stack[++sidx] = buf*buf*buf*buf;
1131  continue;
1132  case cmVARMUL:
1133  Stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2;
1134  continue;
1135  // Next is treatment of numeric functions
1136  case cmFUNC:
1137  {
1138  int iArgCount = pTok->Fun.argc;
1139 
1140 QT_WARNING_PUSH
1141 QT_WARNING_DISABLE_CLANG("-Wundefined-reinterpret-cast")
1142 QT_WARNING_DISABLE_MSVC(4191)
1143  void* fPtr = reinterpret_cast<void*>(pTok->Fun.ptr);
1144  // switch according to argument count
1145  switch (iArgCount)
1146  {
1147  case 0:
1148  sidx += 1;
1149  Stack[sidx] = (*reinterpret_cast<fun_type0>(fPtr))();
1150  continue;
1151  case 1:
1152  Stack[sidx] = (*reinterpret_cast<fun_type1>(fPtr))(Stack[sidx]);
1153  continue;
1154  case 2:
1155  sidx -= 1;
1156  Stack[sidx] = (*reinterpret_cast<fun_type2>(fPtr))(Stack[sidx], Stack[sidx+1]);
1157  continue;
1158  case 3:
1159  sidx -= 2;
1160  Stack[sidx] = (*reinterpret_cast<fun_type3>(fPtr))(Stack[sidx], Stack[sidx+1],
1161  Stack[sidx+2]);
1162  continue;
1163  case 4:
1164  sidx -= 3;
1165  Stack[sidx] = (*reinterpret_cast<fun_type4>(fPtr))(Stack[sidx], Stack[sidx+1],
1166  Stack[sidx+2], Stack[sidx+3]);
1167  continue;
1168  case 5:
1169  sidx -= 4;
1170  Stack[sidx] = (*reinterpret_cast<fun_type5>(fPtr))(Stack[sidx], Stack[sidx+1],
1171  Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]);
1172  continue;
1173  case 6:
1174  sidx -= 5;
1175  Stack[sidx] = (*reinterpret_cast<fun_type6>(fPtr))(Stack[sidx], Stack[sidx+1],
1176  Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]);
1177  continue;
1178  case 7:
1179  sidx -= 6;
1180  Stack[sidx] = (*reinterpret_cast<fun_type7>(fPtr))(Stack[sidx], Stack[sidx+1],
1181  Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]);
1182  continue;
1183  case 8:
1184  sidx -= 7;
1185  Stack[sidx] = (*reinterpret_cast<fun_type8>(fPtr))(Stack[sidx], Stack[sidx+1],
1186  Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6],
1187  Stack[sidx+7]);
1188  continue;
1189  case 9:
1190  sidx -= 8;
1191  Stack[sidx] = (*reinterpret_cast<fun_type9>(fPtr))(Stack[sidx], Stack[sidx+1],
1192  Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6],
1193  Stack[sidx+7], Stack[sidx+8]);
1194  continue;
1195  case 10:
1196  sidx -= 9;
1197  Stack[sidx] = (*reinterpret_cast<fun_type10>(fPtr))(Stack[sidx], Stack[sidx+1],
1198  Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6],
1199  Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]);
1200  continue;
1201  default:
1202  if (iArgCount>0) // function with variable arguments store the number as a negative value
1203  {
1204  Error(ecINTERNAL_ERROR, 1);
1205  }
1206 
1207  sidx -= -iArgCount - 1;
1208  Stack[sidx] =(*reinterpret_cast<multfun_type>(fPtr))(&Stack[sidx], -iArgCount);
1209  continue;
1210  }
1211  }
1212  // Next is treatment of string functions
1213  case cmFUNC_STR:
1214  {
1215  sidx -= pTok->Fun.argc -1;
1216 
1217  // The index of the string argument in the string table
1218  int iIdxStack = pTok->Fun.idx;
1219  void* fPtr = reinterpret_cast<void*>(pTok->Fun.ptr);
1220  Q_ASSERT( iIdxStack>=0 && iIdxStack<m_vStringBuf.size() );
1221 
1222  switch (pTok->Fun.argc) // switch according to argument count
1223  {
1224  case 0:
1225  Stack[sidx] = (*reinterpret_cast<strfun_type1>(fPtr))(m_vStringBuf.at(iIdxStack));
1226  continue;
1227  case 1:
1228  Stack[sidx] = (*reinterpret_cast<strfun_type2>(fPtr))(m_vStringBuf.at(iIdxStack),
1229  Stack[sidx]);
1230  continue;
1231  case 2:
1232  Stack[sidx] = (*reinterpret_cast<strfun_type3>(fPtr))(m_vStringBuf.at(iIdxStack),
1233  Stack[sidx], Stack[sidx+1]);
1234  continue;
1235  default:
1236  break;
1237  }
1238 
1239  continue;
1240  }
1241  case cmFUNC_BULK:
1242  {
1243  int iArgCount = pTok->Fun.argc;
1244 
1245  void* fPtr = reinterpret_cast<void*>(pTok->Fun.ptr);
1246  // switch according to argument count
1247  switch (iArgCount)
1248  {
1249  case 0:
1250  sidx += 1;
1251  Stack[sidx] = (*reinterpret_cast<bulkfun_type0>(fPtr))(nOffset, nThreadID);
1252  continue;
1253  case 1:
1254  Stack[sidx] = (*reinterpret_cast<bulkfun_type1>(fPtr))(nOffset, nThreadID,
1255  Stack[sidx]);
1256  continue;
1257  case 2:
1258  sidx -= 1;
1259  Stack[sidx] = (*reinterpret_cast<bulkfun_type2>(fPtr))(nOffset, nThreadID, Stack[sidx],
1260  Stack[sidx+1]);
1261  continue;
1262  case 3:
1263  sidx -= 2;
1264  Stack[sidx] = (*reinterpret_cast<bulkfun_type3>(fPtr))(nOffset, nThreadID, Stack[sidx],
1265  Stack[sidx+1], Stack[sidx+2]);
1266  continue;
1267  case 4:
1268  sidx -= 3;
1269  Stack[sidx] = (*reinterpret_cast<bulkfun_type4>(fPtr))(nOffset, nThreadID, Stack[sidx],
1270  Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]);
1271  continue;
1272  case 5:
1273  sidx -= 4;
1274  Stack[sidx] = (*reinterpret_cast<bulkfun_type5>(fPtr))(nOffset, nThreadID, Stack[sidx],
1275  Stack[sidx+1], Stack[sidx+2], Stack[sidx+3],
1276  Stack[sidx+4]);
1277  continue;
1278  case 6:
1279  sidx -= 5;
1280  Stack[sidx] = (*reinterpret_cast<bulkfun_type6>(fPtr))(nOffset, nThreadID, Stack[sidx],
1281  Stack[sidx+1], Stack[sidx+2],
1282  Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]);
1283  continue;
1284  case 7:
1285  sidx -= 6;
1286  Stack[sidx] = (*reinterpret_cast<bulkfun_type7>(fPtr))(nOffset, nThreadID, Stack[sidx],
1287  Stack[sidx+1], Stack[sidx+2], Stack[sidx+3],
1288  Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]);
1289  continue;
1290  case 8:
1291  sidx -= 7;
1292  Stack[sidx] = (*reinterpret_cast<bulkfun_type8>(fPtr))(nOffset, nThreadID, Stack[sidx],
1293  Stack[sidx+1], Stack[sidx+2], Stack[sidx+3],
1294  Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]);
1295  continue;
1296  case 9:
1297  sidx -= 8;
1298  Stack[sidx] = (*reinterpret_cast<bulkfun_type9>(fPtr))(nOffset, nThreadID, Stack[sidx],
1299  Stack[sidx+1], Stack[sidx+2], Stack[sidx+3],
1300  Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]);
1301  continue;
1302  case 10:
1303  sidx -= 9;
1304  Stack[sidx] = (*reinterpret_cast<bulkfun_type10>(fPtr))(nOffset, nThreadID,
1305  Stack[sidx],
1306  Stack[sidx+1], Stack[sidx+2], Stack[sidx+3],
1307  Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8],
1308  Stack[sidx+9]);
1309  continue;
1310  default:
1311  Error(ecINTERNAL_ERROR, 2);
1312  continue;
1313  }
1314  }
1315  case cmSTRING:
1316  case cmOPRT_BIN:
1317  case cmOPRT_POSTFIX:
1318  case cmOPRT_INFIX:
1319  // Q_ASSERT(INVALID_CODE_IN_BYTECODE);
1320  // continue;
1321  case cmEND:
1322  // return Stack[m_nFinalResultIdx];
1323  case cmPOW2:
1324  case cmUNKNOWN:
1325  case cmBO: // unused, listed for compiler optimization purposes
1326  case cmBC:
1327  // Q_ASSERT(INVALID_CODE_IN_BYTECODE);
1328  // continue;
1329  case cmARG_SEP:
1330  // Q_ASSERT(INVALID_CODE_IN_BYTECODE);
1331  // continue;
1332  default:
1333  Error(ecINTERNAL_ERROR, 3);
1334  return 0;
1335  } // switch CmdCode
1336 
1338 
1339  } // for all bytecode tokens
1340 
1341  return Stack[m_nFinalResultIdx];
1342 }
1343 
1344 //---------------------------------------------------------------------------------------------------------------------
1345 void QmuParserBase::CreateRPN() const
1346 {
1347  if (m_pTokenReader->GetExpr().length() == false)
1348  {
1349  Error(ecUNEXPECTED_EOF, 0);
1350  }
1351 
1352  QStack<token_type> stOpt, stVal;
1353  QStack<int> stArgCount;
1354  token_type opta, opt; // for storing operators
1355  //token_type val, tval; // for storing value
1356  //string_type strBuf; // buffer for string function arguments
1357 
1358  ReInit();
1359 
1360  // The outermost counter counts the number of seperated items
1361  // such as in "a=10,b=20,c=c+a"
1362  stArgCount.push(1);
1363 
1364  for (;;)
1365  {
1366  opt = m_pTokenReader->ReadNextToken(m_locale, m_decimalPoint, m_thousandsSeparator);
1367 
1368  switch (opt.GetCode())
1369  {
1370  //
1371  // Next three are different kind of value entries
1372  //
1373  case cmSTRING:
1374  {
1375  opt.SetIdx(m_vStringBuf.size()); // Assign buffer index to token
1376  stVal.push(opt);
1377  const QString &str = opt.GetAsString();
1378  m_vStringBuf.push_back(str); // Store string in internal buffer
1379  m_Tokens.insert(m_pTokenReader->GetPos()-str.length(), str);
1380  break;
1381  }
1382  case cmVAR:
1383  {
1384  stVal.push(opt);
1385  m_vRPN.AddVar( static_cast<qreal*>(opt.GetVar()) );
1386  const QString &str = opt.GetAsString();
1387  m_Tokens.insert(m_pTokenReader->GetPos()-str.length(), str);
1388  break;
1389  }
1390  case cmVAL:
1391  {
1392  stVal.push(opt);
1393  m_vRPN.AddVal( opt.GetVal() );
1394  const QString &str = opt.GetAsString();
1395  m_Numbers.insert(m_pTokenReader->GetPos()-str.length(), str);
1396  break;
1397  }
1398  case cmELSE:
1399  m_nIfElseCounter--;
1400  if (m_nIfElseCounter<0)
1401  {
1402  Error(ecMISPLACED_COLON, m_pTokenReader->GetPos());
1403  }
1404  ApplyRemainingOprt(stOpt, stVal);
1405  m_vRPN.AddIfElse(cmELSE);
1406  stOpt.push(opt);
1407  break;
1408  case cmARG_SEP:
1409  if (stArgCount.empty())
1410  {
1411  Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos());
1412  }
1413  if (stOpt.empty() && allowSubexpressions == false)
1414  {
1415  Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos());
1416  }
1417  ++stArgCount.top();
1418  // fallthrough intentional (no break!)
1420  case cmEND:
1421  ApplyRemainingOprt(stOpt, stVal);
1422  break;
1423  case cmBC:
1424  {
1425  // The argument count for parameterless functions is zero
1426  // by default an opening bracket sets parameter count to 1
1427  // in preparation of arguments to come. If the last token
1428  // was an opening bracket we know better...
1429  if (opta.GetCode()==cmBO)
1430  {
1431  --stArgCount.top();
1432  }
1433 
1434  ApplyRemainingOprt(stOpt, stVal);
1435 
1436  // Check if the bracket content has been evaluated completely
1437  if (stOpt.size() && stOpt.top().GetCode()==cmBO)
1438  {
1439  // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check
1440  // if there is either a function or a sign pending
1441  // neither the opening nor the closing bracket will be pushed back to
1442  // the operator stack
1443  // Check if a function is standing in front of the opening bracket,
1444  // if yes evaluate it afterwards check for infix operators
1445  assert(stArgCount.size());
1446  int iArgCount = stArgCount.pop();
1447 
1448  stOpt.pop(); // Take opening bracket from stack
1449 
1450  if (iArgCount>1 && ( stOpt.size()==0 || (stOpt.top().GetCode()!=cmFUNC &&
1451  stOpt.top().GetCode()!=cmFUNC_BULK &&
1452  stOpt.top().GetCode()!=cmFUNC_STR) ) )
1453  {
1454  Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos());
1455  }
1456 
1457  // The opening bracket was popped from the stack now check if there
1458  // was a function before this bracket
1459  if (stOpt.size() && stOpt.top().GetCode()!=cmOPRT_INFIX && stOpt.top().GetCode()!=cmOPRT_BIN &&
1460  stOpt.top().GetFuncAddr()!=nullptr)
1461  {
1462  ApplyFunc(stOpt, stVal, iArgCount);
1463  }
1464  }
1465  } // if bracket content is evaluated
1466  break;
1467  //
1468  // Next are the binary operator entries
1469  //
1470  //case cmAND: // built in binary operators
1471  //case cmOR:
1472  //case cmXOR:
1473  case cmIF:
1474  m_nIfElseCounter++;
1475  // fallthrough intentional (no break!)
1477  case cmLE:
1478  case cmGE:
1479  case cmNEQ:
1480  case cmEQ:
1481  case cmLT:
1482  case cmGT:
1483  case cmADD:
1484  case cmSUB:
1485  case cmMUL:
1486  case cmDIV:
1487  case cmPOW:
1488  case cmLAND:
1489  case cmLOR:
1490  case cmASSIGN:
1491  case cmOPRT_BIN:
1492  // A binary operator (user defined or built in) has been found.
1493  while ( stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmELSE &&
1494  stOpt.top().GetCode() != cmIF)
1495  {
1496  const token_type &topToken = stOpt.top();
1497  int nPrec1 = GetOprtPrecedence(topToken),
1498  nPrec2 = GetOprtPrecedence(opt);
1499 
1500  const ECmdCode code = topToken.GetCode();
1501  if (code==opt.GetCode())
1502  {
1503  // Deal with operator associativity
1504  EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt);
1505  if ( (eOprtAsct==oaRIGHT && (nPrec1 <= nPrec2)) ||
1506  (eOprtAsct==oaLEFT && (nPrec1 < nPrec2)) )
1507  {
1508  break;
1509  }
1510  }
1511  else if (nPrec1 < nPrec2)
1512  {
1513  // In case the operators are not equal the precedence decides alone...
1514  break;
1515  }
1516  if (code==cmOPRT_INFIX)
1517  {
1518  ApplyFunc(stOpt, stVal, 1);
1519  }
1520  else
1521  {
1522  ApplyBinOprt(stOpt, stVal);
1523  }
1524  } // while ( ... )
1525 
1526  if (opt.GetCode()==cmIF)
1527  {
1528  m_vRPN.AddIfElse(opt.GetCode());
1529  }
1530 
1531  // The operator can't be evaluated right now, push back to the operator stack
1532  stOpt.push(opt);
1533  break;
1534  //
1535  // Last section contains functions and operators implicitely mapped to functions
1536  //
1537  case cmBO:
1538  stArgCount.push(1);
1539  stOpt.push(opt);
1540  break;
1541  case cmOPRT_INFIX:
1542  case cmFUNC:
1543  case cmFUNC_BULK:
1544  case cmFUNC_STR:
1545  stOpt.push(opt);
1546  m_Tokens.insert(m_pTokenReader->GetPos()-opt.GetAsString().length(), opt.GetAsString());
1547  break;
1548  case cmOPRT_POSTFIX:
1549  stOpt.push(opt);
1550  ApplyFunc(stOpt, stVal, 1); // this is the postfix operator
1551  m_Tokens.insert(m_pTokenReader->GetPos()-opt.GetAsString().length(), opt.GetAsString());
1552  break;
1553  case cmENDIF:
1554  case cmVARPOW2:
1555  case cmVARPOW3:
1556  case cmVARPOW4:
1557  case cmVARMUL:
1558  case cmPOW2:
1559  case cmUNKNOWN:
1560  default:
1561  Error(ecINTERNAL_ERROR, 3);
1562  } // end of switch operator-token
1563 
1564  opta = opt;
1565 
1566  if ( opt.GetCode() == cmEND )
1567  {
1568  m_vRPN.Finalize();
1569  break;
1570  }
1571 
1572  if (QmuParserBase::g_DbgDumpStack)
1573  {
1574  StackDump(stVal, stOpt);
1575  m_vRPN.AsciiDump();
1576  }
1577  } // while (true)
1578 
1579  if (QmuParserBase::g_DbgDumpCmdCode)
1580  {
1581  m_vRPN.AsciiDump();
1582  }
1583 
1584  if (m_nIfElseCounter>0)
1585  {
1586  Error(ecMISSING_ELSE_CLAUSE);
1587  }
1588 
1589  // get the last value (= final result) from the stack
1590  Q_ASSERT(stArgCount.size()==1);
1591  m_nFinalResultIdx = stArgCount.top();
1592  if (m_nFinalResultIdx==0)
1593  {
1594  Error(ecINTERNAL_ERROR, 9);
1595  }
1596 
1597  if (stVal.size()==0)
1598  {
1599  Error(ecEMPTY_EXPRESSION);
1600  }
1601 
1602  if (stVal.top().GetType()!=tpDBL)
1603  {
1604  Error(ecSTR_RESULT);
1605  }
1606 
1607  m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads);
1608 }
1609 
1610 //---------------------------------------------------------------------------------------------------------------------
1611 /**
1612  * @brief One of the two main parse functions.
1613  * @sa ParseCmdCode(...)
1614  *
1615  * Parse expression from input string. Perform syntax checking and create bytecode. After parsing the string and
1616  * creating the bytecode the function pointer #m_pParseFormula will be changed to the second parse routine the
1617  * uses bytecode instead of string parsing.
1618  */
1619 qreal QmuParserBase::ParseString() const
1620 {
1621  try
1622  {
1623  CreateRPN();
1624  m_pParseFormula = &QmuParserBase::ParseCmdCode;
1625  return (this->*m_pParseFormula)();
1626  }
1627  catch (qmu::QmuParserError &exc)
1628  {
1629  exc.SetFormula(m_pTokenReader->GetExpr());
1630  throw;
1631  }
1632 }
1633 
1634 //---------------------------------------------------------------------------------------------------------------------
1635 /**
1636 * @brief Create an error containing the parse error position.
1637 *
1638 * This function will create an Parser Exception object containing the error text and its position.
1639 *
1640 * @param a_iErrc [in] The error code of type #EErrorCodes.
1641 * @param a_iPos [in] The position where the error was detected.
1642 * @param a_sTok [in] The token string representation associated with the error.
1643 * @throw ParserException always throws thats the only purpose of this function.
1644 */
1645 void Q_NORETURN QmuParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const QString &a_sTok) const
1646 {
1647  throw qmu::QmuParserError (a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos);
1648 }
1649 
1650 //---------------------------------------------------------------------------------------------------------------------
1651 /**
1652  * @brief Clear all user defined variables.
1653  * @throw nothrow
1654  *
1655  * Resets the parser to string parsing mode by calling #ReInit.
1656  */
1657 // cppcheck-suppress unusedFunction
1658 void QmuParserBase::ClearVar()
1659 {
1660  m_VarDef.clear();
1661  ReInit();
1662 }
1663 
1664 //---------------------------------------------------------------------------------------------------------------------
1665 /**
1666  * @brief Remove a variable from internal storage.
1667  * @throw nothrow
1668  *
1669  * Removes a variable if it exists. If the Variable does not exist nothing will be done.
1670  */
1671 void QmuParserBase::RemoveVar(const QString &a_strVarName)
1672 {
1673  varmap_type::iterator item = m_VarDef.find(a_strVarName);
1674  if (item!=m_VarDef.end())
1675  {
1676  m_VarDef.erase(item);
1677  ReInit();
1678  }
1679 }
1680 
1681 //---------------------------------------------------------------------------------------------------------------------
1682 /**
1683  * @brief Clear all functions.
1684  * @post Resets the parser to string parsing mode.
1685  * @throw nothrow
1686  */
1687 // cppcheck-suppress unusedFunction
1688 void QmuParserBase::ClearFun()
1689 {
1690  m_FunDef.clear();
1691  ReInit();
1692 }
1693 
1694 //---------------------------------------------------------------------------------------------------------------------
1695 /**
1696  * @brief Clear all user defined constants.
1697  *
1698  * Both numeric and string constants will be removed from the internal storage.
1699  * @post Resets the parser to string parsing mode.
1700  * @throw nothrow
1701  */
1702 void QmuParserBase::ClearConst()
1703 {
1704  m_ConstDef.clear();
1705  m_StrVarDef.clear();
1706  ReInit();
1707 }
1708 
1709 //---------------------------------------------------------------------------------------------------------------------
1710 /**
1711  * @brief Clear all user defined postfix operators.
1712  * @post Resets the parser to string parsing mode.
1713  * @throw nothrow
1714  */
1715 void QmuParserBase::ClearPostfixOprt()
1716 {
1717  m_PostOprtDef.clear();
1718  ReInit();
1719 }
1720 
1721 //---------------------------------------------------------------------------------------------------------------------
1722 /**
1723  * @brief Clear all user defined binary operators.
1724  * @post Resets the parser to string parsing mode.
1725  * @throw nothrow
1726  */
1727 // cppcheck-suppress unusedFunction
1728 void QmuParserBase::ClearOprt()
1729 {
1730  m_OprtDef.clear();
1731  ReInit();
1732 }
1733 
1734 //---------------------------------------------------------------------------------------------------------------------
1735 /**
1736  * @brief Clear the user defined Prefix operators.
1737  * @post Resets the parser to string parser mode.
1738  * @throw nothrow
1739  */
1740 // cppcheck-suppress unusedFunction
1741 void QmuParserBase::ClearInfixOprt()
1742 {
1743  m_InfixOprtDef.clear();
1744  ReInit();
1745 }
1746 
1747 //---------------------------------------------------------------------------------------------------------------------
1748 /**
1749  * @brief Enable or disable the formula optimization feature.
1750  * @post Resets the parser to string parser mode.
1751  * @throw nothrow
1752  */
1753 void QmuParserBase::EnableOptimizer(bool a_bIsOn)
1754 {
1755  m_vRPN.EnableOptimizer(a_bIsOn);
1756  ReInit();
1757 }
1758 
1759 //---------------------------------------------------------------------------------------------------------------------
1760 /**
1761  * @brief Enable the dumping of bytecode amd stack content on the console.
1762  * @param bDumpCmd Flag to enable dumping of the current bytecode to the console.
1763  * @param bDumpStack Flag to enable dumping of the stack content is written to the console.
1764  *
1765  * This function is for debug purposes only!
1766  */
1767 // cppcheck-suppress unusedFunction
1768 void QmuParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack)
1769 {
1770  QmuParserBase::g_DbgDumpCmdCode = bDumpCmd;
1771  QmuParserBase::g_DbgDumpStack = bDumpStack;
1772 }
1773 
1774 //---------------------------------------------------------------------------------------------------------------------
1775 /**
1776  * @brief Enable or disable the built in binary operators.
1777  * @throw nothrow
1778  * @sa m_bBuiltInOp, ReInit()
1779  *
1780  * If you disable the built in binary operators there will be no binary operators defined. Thus you must add them
1781  * manually one by one. It is not possible to disable built in operators selectively. This function will Reinitialize
1782  * the parser by calling ReInit().
1783  */
1784 void QmuParserBase::EnableBuiltInOprt(bool a_bIsOn)
1785 {
1786  m_bBuiltInOp = a_bIsOn;
1787  ReInit();
1788 }
1789 
1790 //---------------------------------------------------------------------------------------------------------------------
1791 /**
1792  * @brief Get the argument separator character.
1793  */
1794 QChar QmuParserBase::GetArgSep() const
1795 {
1796  return m_pTokenReader->GetArgSep();
1797 }
1798 
1799 //---------------------------------------------------------------------------------------------------------------------
1800 /**
1801  * @brief Set argument separator.
1802  * @param cArgSep the argument separator character.
1803  */
1804 void QmuParserBase::SetArgSep(char_type cArgSep)
1805 {
1806  m_pTokenReader->SetArgSep(cArgSep);
1807 }
1808 
1809 //---------------------------------------------------------------------------------------------------------------------
1810 /**
1811  * @brief Dump stack content.
1812  *
1813  * This function is used for debugging only.
1814  */
1815 void QmuParserBase::StackDump(const QStack<token_type> &a_stVal, const QStack<token_type> &a_stOprt) const
1816 {
1817  QStack<token_type> stOprt(a_stOprt),
1818  stVal(a_stVal);
1819 
1820  qDebug() << "\nValue stack:\n";
1821  while ( stVal.empty() == false )
1822  {
1823  token_type val = stVal.pop();
1824  if (val.GetType()==tpSTR)
1825  {
1826  qDebug() << " \"" << val.GetAsString() << "\" ";
1827  }
1828  else
1829  {
1830  qDebug() << " " << val.GetVal() << " ";
1831  }
1832  }
1833  qDebug() << "\nOperator stack:\n";
1834 
1835  while ( stOprt.empty() == false )
1836  {
1837  const token_type &topToken = stOprt.top();
1838  if (topToken.GetCode()<=cmASSIGN)
1839  {
1840  qDebug() << "OPRT_INTRNL \"" << QmuParserBase::c_DefaultOprt[topToken.GetCode()] << "\" \n";
1841  }
1842  else
1843  {
1844  switch ( topToken.GetCode())
1845  {
1846  case cmVAR:
1847  qDebug() << "VAR\n";
1848  break;
1849  case cmVAL:
1850  qDebug() << "VAL\n";
1851  break;
1852  case cmFUNC:
1853  qDebug() << "FUNC \"" << topToken.GetAsString() << "\"\n";
1854  break;
1855  case cmFUNC_BULK:
1856  qDebug() << "FUNC_BULK \"" << topToken.GetAsString() << "\"\n";
1857  break;
1858  case cmOPRT_INFIX:
1859  qDebug() << "OPRT_INFIX \"" << topToken.GetAsString() << "\"\n";
1860  break;
1861  case cmOPRT_BIN:
1862  qDebug() << "OPRT_BIN \"" << topToken.GetAsString() << "\"\n";
1863  break;
1864  case cmFUNC_STR:
1865  qDebug() << "FUNC_STR\n";
1866  break;
1867  case cmEND:
1868  qDebug() << "END\n";
1869  break;
1870  case cmUNKNOWN:
1871  qDebug() << "UNKNOWN\n";
1872  break;
1873  case cmBO:
1874  qDebug() << "BRACKET \"(\"\n";
1875  break;
1876  case cmBC:
1877  qDebug() << "BRACKET \")\"\n";
1878  break;
1879  case cmIF:
1880  qDebug() << "IF\n";
1881  break;
1882  case cmELSE:
1883  qDebug() << "ELSE\n";
1884  break;
1885  case cmENDIF:
1886  qDebug() << "ENDIF\n";
1887  break;
1888  default:
1889  qDebug() << topToken.GetCode() << " ";
1890  break;
1891  }
1892  }
1893  stOprt.pop();
1894  }
1895  qDebug() << Qt::dec;
1896 }
1897 
1898 //---------------------------------------------------------------------------------------------------------------------
1899 /** @brief Evaluate an expression containing comma seperated subexpressions
1900  * @param [out] nStackSize The total number of results available
1901  * @return Pointer to the array containing all expression results
1902  *
1903  * This member function can be used to retriev all results of an expression made up of multiple comma seperated
1904  * subexpressions (i.e. "x+y,sin(x),cos(y)")
1905  */
1906 qreal* QmuParserBase::Eval(int &nStackSize) const
1907 {
1908  (this->*m_pParseFormula)();
1909  nStackSize = m_nFinalResultIdx;
1910 
1911  // (for historic reasons the stack starts at position 1)
1912  return &m_vStackBuffer[1];
1913 }
1914 
1915 //---------------------------------------------------------------------------------------------------------------------
1916 void QmuParserBase::Eval(qreal *results, int nBulkSize) const
1917 {
1918  CreateRPN();
1919 
1920  int i = 0;
1921 
1922  #ifdef QMUP_USE_OPENMP
1923  //#define DEBUG_OMP_STUFF
1924  #ifdef DEBUG_OMP_STUFF
1925  int *pThread = new int[nBulkSize];
1926  int *pIdx = new int[nBulkSize];
1927  #endif
1928 
1929  int nMaxThreads = qMin(omp_get_max_threads(), s_MaxNumOpenMPThreads);
1930  // cppcheck-suppress unreadVariable
1931  int ct=0;
1932  omp_set_num_threads(nMaxThreads);
1933 
1934  #pragma omp parallel for schedule(static, nBulkSize/nMaxThreads) private(nThreadID)
1935  for (i=0; i<nBulkSize; ++i)
1936  {
1937  int nThreadID = omp_get_thread_num();
1938  results[i] = ParseCmdCodeBulk(i, nThreadID);
1939 
1940  #ifdef DEBUG_OMP_STUFF
1941  #pragma omp critical
1942  {
1943  pThread[ct] = nThreadID;
1944  pIdx[ct] = i;
1945  ct++;
1946  }
1947  #endif
1948  }
1949 
1950  #ifdef DEBUG_OMP_STUFF
1951  FILE *pFile = fopen("bulk_dbg.txt", "w");
1952  for (i=0; i<nBulkSize; ++i)
1953  {
1954  fprintf(pFile, "idx: %d thread: %d \n", pIdx[i], pThread[i]);
1955  }
1956 
1957  delete [] pIdx;
1958  delete [] pThread;
1959 
1960  fclose(pFile);
1961  #endif
1962 
1963  #else
1964  for (i=0; i<nBulkSize; ++i)
1965  {
1966  results[i] = ParseCmdCodeBulk(i, 0);
1967  }
1968  #endif
1969 }
1970 
1971 //---------------------------------------------------------------------------------------------------------------------
1972 /**
1973  * @brief Set a function that can create variable pointer for unknown expression variables.
1974  * @param a_pFactory A pointer to the variable factory.
1975  * @param pUserData A user defined context pointer.
1976  */
1977 // cppcheck-suppress unusedFunction
1978 void qmu::QmuParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData)
1979 {
1980  m_pTokenReader->SetVarCreator(a_pFactory, pUserData);
1981 }
1982 
1983 } // namespace qmu
Mathematical expressions parser (base parser engine).
Definition: qmuparserbase.h:66
void setDecimalPoint(const QChar &c)
void CheckOprt(const QString &a_sName, const QmuParserCallback &a_Callback, const QString &a_szCharSet) const
Check if a name contains invalid characters.
void Assign(const QmuParserBase &a_Parser)
Copy state of a parser object to this.
void AddCallback(const QString &a_strName, const QmuParserCallback &a_Callback, funmap_type &a_Storage, const QString &a_szCharSet)
Add a function or operator callback to the parser.
void CheckName(const QString &a_sName, const QString &a_szCharSet) const
Check if a name contains invalid characters.
QLocale getLocale() const
void InitTokenReader()
Initialize the token reader.
funmap_type m_OprtDef
Binary operator callbacks.
void SetArgSep(char_type cArgSep)
Set argument separator.
valbuf_type m_vStackBuffer
This is merely a buffer used for the stack in the cmd parsing routine.
QmuParserByteCode m_vRPN
The Bytecode class.
static QString GetVersion(EParserVersionInfo eInfo=pviFULL)
Returns the version of muparser.
stringbuf_type m_vStringVarBuf
void DefineStrConst(const QString &a_strName, const QString &a_strVal)
Define a new string constant.
void DefineOprt(const QString &a_sName, fun_type2 a_pFun, unsigned a_iPrec=0, EOprtAssociativity a_eAssociativity=oaLEFT, bool a_bAllowOpt=false)
Define a binary operator.
void setAllowSubexpressions(bool value)
EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const
Get operator priority.
static const QStringList c_DefaultOprt
Identifiers for built in binary operators.
valmap_type m_ConstDef
user constants.
int GetOprtPrecedence(const token_type &a_Tok) const
Get operator priority.
QmuParserTokenReader token_reader_type
Typedef for the token reader.
strmap_type m_StrVarDef
user defined string constants
funmap_type m_FunDef
Map of function names and pointers.
void Q_NORETURN Error(EErrorCodes a_iErrc, int a_iPos=-1, const QString &a_sTok=QString()) const
Create an error containing the parse error position.
funmap_type m_PostOprtDef
Postfix operator callbacks.
void ReInit() const
Reset parser to string parsing mode and clear internal buffers.
void DefineVar(const QString &a_sName, qreal *a_pVar)
Add a user defined variable.
void ApplyRemainingOprt(QStack< token_type > &a_stOpt, QStack< token_type > &a_stVal) const
Apply a binary operator.
virtual void InitConst()=0
const QString & ValidNameChars() const
Virtual function that defines the characters allowed in name identifiers.
QString m_sInfixOprtChars
Charset for infix operator tokens.
static const int s_MaxNumOpenMPThreads
Maximum number of threads spawned by OpenMP when using the bulk mode.
QChar getDecimalPoint() const
int m_nIfElseCounter
Internal counter for keeping track of nested if-then-else clauses.
qreal ParseCmdCodeBulk(int nOffset, int nThreadID) const
Evaluate the RPN.
QLocale m_locale
The locale used by the parser.
QMap< int, QString > m_Numbers
Keep all numbers what exist in formula.
void Init()
Initialize user defined functions.
QChar getThousandsSeparator() const
void ApplyFunc(QStack< token_type > &a_stOpt, QStack< token_type > &a_stVal, int iArgCount) const
Apply a function token.
funmap_type m_InfixOprtDef
unary infix operator.
bool m_bBuiltInOp
Flag that can be used for switching built in operators on and off.
void CreateRPN() const
static bool g_DbgDumpStack
void ApplyBinOprt(QStack< token_type > &a_stOpt, QStack< token_type > &a_stVal) const
Performs the necessary steps to write code for the execution of binary operators into the bytecode.
void setThousandsSeparator(const QChar &c)
void DefinePostfixOprt(const QString &a_sFun, fun_type1 a_pFun, bool a_bAllowOpt=true)
Add a user defined operator.
const varmap_type & GetUsedVar() const
Return a map containing the used variables only.
virtual void InitFun()=0
stringbuf_type m_vStringBuf
String buffer, used for storing string function arguments.
token_type ApplyStrFunc(const token_type &a_FunTok, const QVector< token_type > &a_vArg) const
Execute a function that takes a single string argument.
void SetExpr(const QString &a_sExpr)
Set the formula.
QMap< int, QString > m_Tokens
Keep all tokens that we can translate.
void setLocale(const QLocale &value)
void SetVarFactory(facfun_type a_pFactory, void *pUserData=nullptr)
Set a function that can create variable pointer for unknown expression variables.
qreal ParseCmdCode() const
Parse the command code.
void ResetLocale()
Resets the locale.
virtual void OnDetectVar(const QString &pExpr, int &nStart, int &nEnd)
const QString & ValidInfixOprtChars() const
Virtual function that defines the characters allowed in infix operator definitions.
virtual void InitCharSets()=0
const QString & ValidOprtChars() const
Virtual function that defines the characters allowed in operator definitions.
QString m_sOprtChars
Charset for postfix/ binary operator tokens.
QmuParserBase()
Constructor.
std::unique_ptr< token_reader_type > m_pTokenReader
Managed pointer to the token reader object.
ParseFunction m_pParseFormula
Pointer to the parser function.
varmap_type m_VarDef
user defind variables.
qreal ParseString() const
One of the two main parse functions.
static bool g_DbgDumpCmdCode
void ApplyIfElse(QStack< token_type > &a_stOpt, QStack< token_type > &a_stVal) const
void DefineConst(const QString &a_sName, qreal a_fVal)
Add a user defined constant.
QmuParserBase & operator=(const QmuParserBase &a_Parser)
Assignement operator.
virtual void InitOprt()=0
void DefineInfixOprt(const QString &a_sName, fun_type1 a_pFun, int a_iPrec=prINFIX, bool a_bAllowOpt=true)
Add a user defined operator.
QString m_sNameChars
Charset for names.
void AddIfElse(ECmdCode a_Oprt)
void AddFun(generic_fun_type a_pFun, int a_iArgc)
Add function to bytecode.
const SToken * GetBase() const
void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx)
Add Strung function entry to the parser bytecode.
void AddOp(ECmdCode a_Oprt)
Add an operator identifier to bytecode.
void clear()
Delete the bytecode.
void AddBulkFun(generic_fun_type a_pFun, int a_iArgc)
Add a bulk function to bytecode.
void AddAssignOp(qreal *a_pVar)
Add an assignement operator.
Encapsulation of prototypes for a numerical parser function.
ECmdCode GetCode() const
Return the callback code.
void * GetAddr() const
Get the callback address for the parser function.
Error class of the parser.
void SetFormula(const QString &a_strFormula)
Set the expression related to this error.
ETypeCode GetType() const
EOprtAssociativity GetAssociativity() const
generic_fun_type GetFuncAddr() const
Return the address of the callback function assoziated with function and operator tokens.
void SetIdx(int a_iIdx)
Set an index associated with the token related data.
ECmdCode GetCode() const
Return the token type.
QmuParserToken & SetVal(TBase a_fVal, const TString &a_strTok=TString())
Make this token a value token.
int GetArgCount() const
Return the number of function arguments.
const TString & GetAsString() const
Return the token identifier.
TBase GetVal() const
Get value of the token.
TBase * GetVar() const
Get address of a variable token.
Namespace for mathematical applications.
qreal(* bulkfun_type10)(int, int, qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:287
std::map< QString, QmuParserCallback > funmap_type
Container for Callback objects.
string_type::value_type char_type
The character type used by the parser.
Definition: qmuparserdef.h:202
qreal(* bulkfun_type4)(int, int, qreal, qreal, qreal, qreal)
Callback type used for functions with four arguments.
Definition: qmuparserdef.h:269
qreal(* fun_type7)(qreal, qreal, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:245
qreal(* fun_type10)(qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:254
qreal(* fun_type3)(qreal, qreal, qreal)
Callback type used for functions with three arguments.
Definition: qmuparserdef.h:233
qreal(* fun_type8)(qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:248
EErrorCodes
Error codes.
@ ecTOO_FEW_PARAMS
Too few function parameters. (Example: "ite(1<2;2)")
@ ecUNEXPECTED_OPERATOR
Unexpected binary operator found.
@ ecOPRT_TYPE_CONFLICT
binary operators may only be applied to value items of the same type
@ ecINVALID_NAME
Invalid function, variable or constant name.
@ ecLOCALE
Conflict with current locale.
@ ecINVALID_INFIX_IDENT
Invalid function, variable or constant name.
@ ecBUILTIN_OVERLOAD
Trying to overload builtin operator.
@ ecUNEXPECTED_EOF
Unexpected end of formula. (Example: "2+sin(")
@ ecINVALID_FUN_PTR
Invalid callback function pointer.
@ ecSTRING_EXPECTED
A string function has been called with a different type of argument.
@ ecNAME_CONFLICT
Name conflict.
@ ecVAL_EXPECTED
A numerical function has been called with a non value type of argument.
@ ecMISSING_ELSE_CLAUSE
@ ecUNASSIGNABLE_TOKEN
Token cant be identified.
@ ecUNEXPECTED_ARG_SEP
An unexpected semicolon has been found. (Example: "1;23")
@ ecUNEXPECTED_ARG
An unexpected argument has been found.
@ ecSTR_RESULT
result is a string
@ ecEMPTY_EXPRESSION
The Expression is empty.
@ ecINVALID_POSTFIX_IDENT
Invalid function, variable or constant name.
@ ecTOO_MANY_PARAMS
Too many function parameters.
@ ecINTERNAL_ERROR
Internal error of any kind.
@ ecINVALID_VAR_PTR
Invalid variable pointer.
@ ecDIV_BY_ZERO
Division by zero (currently unused)
@ ecMISPLACED_COLON
qreal *(* facfun_type)(const QString &, void *)
Callback used for variable creation factory functions.
Definition: qmuparserdef.h:306
qreal(* bulkfun_type5)(int, int, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:272
ECmdCode
Bytecode values.
Definition: qmuparserdef.h:99
@ cmVARPOW4
Definition: qmuparserdef.h:129
@ cmOPRT_INFIX
code for infix operators
Definition: qmuparserdef.h:140
@ cmBC
Operator item: closing bracket.
Definition: qmuparserdef.h:118
@ cmLE
Operator item: less or equal.
Definition: qmuparserdef.h:103
@ cmUNKNOWN
uninitialized item
Definition: qmuparserdef.h:142
@ cmSUB
Operator item: subtract.
Definition: qmuparserdef.h:110
@ cmLAND
Definition: qmuparserdef.h:114
@ cmGT
Operator item: greater than.
Definition: qmuparserdef.h:108
@ cmSTRING
Code for a string token.
Definition: qmuparserdef.h:137
@ cmFUNC
Code for a generic function item.
Definition: qmuparserdef.h:134
@ cmVARMUL
Definition: qmuparserdef.h:130
@ cmEND
end of formula
Definition: qmuparserdef.h:141
@ cmFUNC_STR
Code for a function with a string parameter.
Definition: qmuparserdef.h:135
@ cmLT
Operator item: less than.
Definition: qmuparserdef.h:107
@ cmMUL
Operator item: multiply.
Definition: qmuparserdef.h:111
@ cmVARPOW3
Definition: qmuparserdef.h:128
@ cmGE
Operator item: greater or equal.
Definition: qmuparserdef.h:104
@ cmADD
Operator item: add.
Definition: qmuparserdef.h:109
@ cmASSIGN
Operator item: Assignment operator.
Definition: qmuparserdef.h:116
@ cmENDIF
For use in the ternary if-then-else operator.
Definition: qmuparserdef.h:121
@ cmELSE
For use in the ternary if-then-else operator.
Definition: qmuparserdef.h:120
@ cmEQ
Operator item: equals.
Definition: qmuparserdef.h:106
@ cmFUNC_BULK
Special callbacks for Bulk mode with an additional parameter for the bulk index.
Definition: qmuparserdef.h:136
@ cmPOW2
Definition: qmuparserdef.h:131
@ cmARG_SEP
function argument separator
Definition: qmuparserdef.h:122
@ cmPOW
Operator item: y to the power of ...
Definition: qmuparserdef.h:113
@ cmLOR
Definition: qmuparserdef.h:115
@ cmNEQ
Operator item: not equal.
Definition: qmuparserdef.h:105
@ cmVARPOW2
Definition: qmuparserdef.h:127
@ cmOPRT_BIN
user defined binary operator
Definition: qmuparserdef.h:138
@ cmIF
For use in the ternary if-then-else operator.
Definition: qmuparserdef.h:119
@ cmVAL
value item
Definition: qmuparserdef.h:124
@ cmOPRT_POSTFIX
code for postfix operators
Definition: qmuparserdef.h:139
@ cmDIV
Operator item: division.
Definition: qmuparserdef.h:112
@ cmVAR
variable item
Definition: qmuparserdef.h:123
@ cmBO
Operator item: opening bracket.
Definition: qmuparserdef.h:117
qreal(* fun_type6)(qreal, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:242
qreal(* fun_type4)(qreal, qreal, qreal, qreal)
Callback type used for functions with four arguments.
Definition: qmuparserdef.h:236
qreal(* fun_type9)(qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:251
qreal(* bulkfun_type1)(int, int, qreal)
Callback type used for functions with a single arguments.
Definition: qmuparserdef.h:260
qreal(* fun_type2)(qreal, qreal)
Callback type used for functions with two arguments.
Definition: qmuparserdef.h:230
qreal(* bulkfun_type2)(int, int, qreal, qreal)
Callback type used for functions with two arguments.
Definition: qmuparserdef.h:263
qreal(* generic_fun_type)()
Callback type used for functions without arguments.
Definition: qmuparserdef.h:221
EParserVersionInfo
Definition: qmuparserdef.h:157
@ pviFULL
Definition: qmuparserdef.h:159
qreal(* bulkfun_type0)(int, int)
Callback type used for functions without arguments.
Definition: qmuparserdef.h:257
qreal(* strfun_type3)(const QString &, qreal, qreal)
Callback type used for functions taking a string and two values as arguments.
Definition: qmuparserdef.h:299
EOprtAssociativity
Parser operator precedence values.
Definition: qmuparserdef.h:165
@ oaNONE
Definition: qmuparserdef.h:168
@ oaLEFT
Definition: qmuparserdef.h:166
@ oaRIGHT
Definition: qmuparserdef.h:167
qreal(* fun_type1)(qreal)
Callback type used for functions with a single arguments.
Definition: qmuparserdef.h:227
qreal(* bulkfun_type7)(int, int, qreal, qreal, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:278
qreal(* multfun_type)(const qreal *, int)
Callback type used for functions with a variable argument list.
Definition: qmuparserdef.h:290
qreal(* strfun_type2)(const QString &, qreal)
Callback type used for functions taking a string and a value as arguments.
Definition: qmuparserdef.h:296
qreal(* fun_type0)()
Callback type used for functions without arguments.
Definition: qmuparserdef.h:224
@ prPOW
power operator priority (highest)
Definition: qmuparserdef.h:182
@ prLAND
Definition: qmuparserdef.h:177
@ prLOR
Definition: qmuparserdef.h:176
@ prADD_SUB
addition
Definition: qmuparserdef.h:180
@ prPOSTFIX
Postfix operator priority (currently unused)
Definition: qmuparserdef.h:186
@ prCMP
comparsion operators
Definition: qmuparserdef.h:179
@ prMUL_DIV
multiplication/division
Definition: qmuparserdef.h:181
qreal(* bulkfun_type6)(int, int, qreal, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:275
qreal(* bulkfun_type8)(int, int, qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:281
qreal(* bulkfun_type3)(int, int, qreal, qreal, qreal)
Callback type used for functions with three arguments.
Definition: qmuparserdef.h:266
qreal(* bulkfun_type9)(int, int, qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:284
@ tpDBL
Floating point variables.
Definition: qmuparserdef.h:151
@ tpSTR
String type (Function arguments and constants only, no string variables)
Definition: qmuparserdef.h:150
std::map< QString, qreal * > varmap_type
Type used for storing variables.
Definition: qmuparserdef.h:210
qreal(* fun_type5)(qreal, qreal, qreal, qreal, qreal)
Callback type used for functions with five arguments.
Definition: qmuparserdef.h:239
qreal(* strfun_type1)(const QString &)
Callback type used for functions taking a string as an argument.
Definition: qmuparserdef.h:293
QT_WARNING_POP static Q_REQUIRED_RESULT bool QmuFuzzyComparePossibleNulls(double p1, double p2)
Definition: qmudef.h:61
This file contains the class definition of the qmuparser engine.
#define QMUP_VERSION
Definition: qmuparserdef.h:35
#define QMUP_VERSION_DATE
Definition: qmuparserdef.h:36
#define QMUP_FALLTHROUGH
Definition: qmuparserdef.h:74