OpcUaCanOpen
CANopen OPC-UA server
muParserBase.cpp
Go to the documentation of this file.
1 /*
2  __________
3  _____ __ __\______ \_____ _______ ______ ____ _______
4  / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
5  | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
6  |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
7  \/ \/ \/ \/
8  Copyright (C) 2011 Ingo Berg
9 
10  Permission is hereby granted, free of charge, to any person obtaining a copy of this
11  software and associated documentation files (the "Software"), to deal in the Software
12  without restriction, including without limitation the rights to use, copy, modify,
13  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
14  permit persons to whom the Software is furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in all copies or
17  substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
20  NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 
26 #include "muParserBase.h"
27 #include "muParserTemplateMagic.h"
28 
29 //--- Standard includes ------------------------------------------------------------------------
30 #include <cassert>
31 #include <algorithm>
32 #include <cmath>
33 #include <memory>
34 #include <vector>
35 #include <deque>
36 #include <sstream>
37 #include <locale>
38 
39 #ifdef MUP_USE_OPENMP
40  #include <omp.h>
41 #endif
42 
43 using namespace std;
44 
49 namespace mu
50 {
51  std::locale ParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep<char_type>('.'));
52 
53  bool ParserBase::g_DbgDumpCmdCode = false;
54  bool ParserBase::g_DbgDumpStack = false;
55 
56  //------------------------------------------------------------------------------
62  const char_type* ParserBase::c_DefaultOprt[] =
63  {
64  _T("<="), _T(">="), _T("!="),
65  _T("=="), _T("<"), _T(">"),
66  _T("+"), _T("-"), _T("*"),
67  _T("/"), _T("^"), _T("&&"),
68  _T("||"), _T("="), _T("("),
69  _T(")"), _T("?"), _T(":"), 0
70  };
71 
72  const int ParserBase::s_MaxNumOpenMPThreads = 16;
73 
74  //------------------------------------------------------------------------------
79  ParserBase::ParserBase()
80  :m_pParseFormula(&ParserBase::ParseString)
81  ,m_vRPN()
82  ,m_vStringBuf()
83  ,m_pTokenReader()
84  ,m_FunDef()
85  ,m_PostOprtDef()
86  ,m_InfixOprtDef()
87  ,m_OprtDef()
88  ,m_ConstDef()
89  ,m_StrVarDef()
90  ,m_VarDef()
91  ,m_bBuiltInOp(true)
92  ,m_sNameChars()
93  ,m_sOprtChars()
94  ,m_sInfixOprtChars()
95  ,m_nIfElseCounter(0)
96  ,m_vStackBuffer()
97  ,m_nFinalResultIdx(0)
98  {
100  }
101 
102  //---------------------------------------------------------------------------
109  :m_pParseFormula(&ParserBase::ParseString)
110  ,m_vRPN()
111  ,m_vStringBuf()
112  ,m_pTokenReader()
113  ,m_FunDef()
114  ,m_PostOprtDef()
115  ,m_InfixOprtDef()
116  ,m_OprtDef()
117  ,m_ConstDef()
118  ,m_StrVarDef()
119  ,m_VarDef()
120  ,m_bBuiltInOp(true)
121  ,m_sNameChars()
122  ,m_sOprtChars()
123  ,m_sInfixOprtChars()
124  ,m_nIfElseCounter(0)
125  {
126  m_pTokenReader.reset(new token_reader_type(this));
127  Assign(a_Parser);
128  }
129 
130  //---------------------------------------------------------------------------
132  {}
133 
134  //---------------------------------------------------------------------------
143  {
144  Assign(a_Parser);
145  return *this;
146  }
147 
148  //---------------------------------------------------------------------------
157  void ParserBase::Assign(const ParserBase &a_Parser)
158  {
159  if (&a_Parser==this)
160  return;
161 
162  // Don't copy bytecode instead cause the parser to create new bytecode
163  // by resetting the parse function.
164  ReInit();
165 
166  m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants
167  m_VarDef = a_Parser.m_VarDef; // Copy user defined variables
168  m_bBuiltInOp = a_Parser.m_bBuiltInOp;
169  m_vStringBuf = a_Parser.m_vStringBuf;
170  m_vStackBuffer = a_Parser.m_vStackBuffer;
172  m_StrVarDef = a_Parser.m_StrVarDef;
173  m_vStringVarBuf = a_Parser.m_vStringVarBuf;
175  m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this));
176 
177  // Copy function and operator callbacks
178  m_FunDef = a_Parser.m_FunDef; // Copy function definitions
179  m_PostOprtDef = a_Parser.m_PostOprtDef; // post value unary operators
180  m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation
181  m_OprtDef = a_Parser.m_OprtDef; // binary operators
182 
183  m_sNameChars = a_Parser.m_sNameChars;
184  m_sOprtChars = a_Parser.m_sOprtChars;
186  }
187 
188  //---------------------------------------------------------------------------
197  {
198  char_type cThousandsSep = std::use_facet< change_dec_sep<char_type> >(s_locale).thousands_sep();
199  s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>(cDecSep, cThousandsSep));
200  }
201 
202  //---------------------------------------------------------------------------
211  {
212  char_type cDecSep = std::use_facet< change_dec_sep<char_type> >(s_locale).decimal_point();
213  s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>(cDecSep, cThousandsSep));
214  }
215 
216  //---------------------------------------------------------------------------
223  {
224  s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>('.'));
225  SetArgSep(',');
226  }
227 
228  //---------------------------------------------------------------------------
238  {
239  m_pTokenReader.reset(new token_reader_type(this));
240  }
241 
242  //---------------------------------------------------------------------------
248  void ParserBase::ReInit() const
249  {
251  m_vStringBuf.clear();
252  m_vRPN.clear();
253  m_pTokenReader->ReInit();
254  m_nIfElseCounter = 0;
255  }
256 
257  //---------------------------------------------------------------------------
258  void ParserBase::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/)
259  {}
260 
261  //---------------------------------------------------------------------------
270  {
272 
273  ss << MUP_VERSION;
274 
275  if (eInfo==pviFULL)
276  {
277  ss << _T(" (") << MUP_VERSION_DATE;
278  ss << std::dec << _T("; ") << sizeof(void*)*8 << _T("BIT");
279 
280 #ifdef _DEBUG
281  ss << _T("; DEBUG");
282 #else
283  ss << _T("; RELEASE");
284 #endif
285 
286 #ifdef _UNICODE
287  ss << _T("; UNICODE");
288 #else
289  #ifdef _MBCS
290  ss << _T("; MBCS");
291  #else
292  ss << _T("; ASCII");
293  #endif
294 #endif
295 
296 #ifdef MUP_USE_OPENMP
297  ss << _T("; OPENMP");
298 //#else
299 // ss << _T("; NO_OPENMP");
300 #endif
301 
302 #if defined(MUP_MATH_EXCEPTIONS)
303  ss << _T("; MATHEXC");
304 //#else
305 // ss << _T("; NO_MATHEXC");
306 #endif
307 
308  ss << _T(")");
309  }
310 
311  return ss.str();
312  }
313 
314  //---------------------------------------------------------------------------
322  {
323  m_pTokenReader->AddValIdent(a_pCallback);
324  }
325 
326  //---------------------------------------------------------------------------
332  {
333  m_pTokenReader->SetVarCreator(a_pFactory, pUserData);
334  }
335 
336  //---------------------------------------------------------------------------
338  void ParserBase::AddCallback( const string_type &a_strName,
339  const ParserCallback &a_Callback,
340  funmap_type &a_Storage,
341  const char_type *a_szCharSet )
342  {
343  if (a_Callback.GetAddr()==0)
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  Error(ecNAME_CONFLICT, -1, a_strName);
351 
352  if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() )
353  Error(ecNAME_CONFLICT, -1, a_strName);
354 
355  if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() )
356  Error(ecNAME_CONFLICT, -1, a_strName);
357 
358  if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() )
359  Error(ecNAME_CONFLICT, -1, a_strName);
360 
361  CheckOprt(a_strName, a_Callback, a_szCharSet);
362  a_Storage[a_strName] = a_Callback;
363  ReInit();
364  }
365 
366  //---------------------------------------------------------------------------
371  void ParserBase::CheckOprt(const string_type &a_sName,
372  const ParserCallback &a_Callback,
373  const string_type &a_szCharSet) const
374  {
375  if ( !a_sName.length() ||
376  (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) ||
377  (a_sName[0]>='0' && a_sName[0]<='9'))
378  {
379  switch(a_Callback.GetCode())
380  {
381  case cmOPRT_POSTFIX: Error(ecINVALID_POSTFIX_IDENT, -1, a_sName); break;
382  case cmOPRT_INFIX: Error(ecINVALID_INFIX_IDENT, -1, a_sName); break;
383  default: Error(ecINVALID_NAME, -1, a_sName);
384  }
385  }
386  }
387 
388  //---------------------------------------------------------------------------
393  void ParserBase::CheckName(const string_type &a_sName,
394  const string_type &a_szCharSet) const
395  {
396  if ( !a_sName.length() ||
397  (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) ||
398  (a_sName[0]>='0' && a_sName[0]<='9'))
399  {
401  }
402  }
403 
404  //---------------------------------------------------------------------------
412  void ParserBase::SetExpr(const string_type &a_sExpr)
413  {
414  // Check locale compatibility
415  if (m_pTokenReader->GetArgSep()==std::use_facet<numpunct<char_type> >(s_locale).decimal_point())
416  Error(ecLOCALE);
417 
418  // <ibg> 20060222: Bugfix for Borland-Kylix:
419  // adding a space to the expression will keep Borlands KYLIX from going wild
420  // when calling tellg on a stringstream created from the expression after
421  // reading a value at the end of an expression. (mu::Parser::IsVal function)
422  // (tellg returns -1 otherwise causing the parser to ignore the value)
423  string_type sBuf(a_sExpr + _T(" ") );
424  m_pTokenReader->SetFormula(sBuf);
425  ReInit();
426  }
427 
428  //---------------------------------------------------------------------------
433  {
434  return (const char_type **)(&c_DefaultOprt[0]);
435  }
436 
437  //---------------------------------------------------------------------------
442  {
444  }
445 
446  //---------------------------------------------------------------------------
451  {
453  }
454 
455  //---------------------------------------------------------------------------
460  {
462  }
463 
464  //---------------------------------------------------------------------------
469  {
470  assert(m_sNameChars.size());
471  return m_sNameChars.c_str();
472  }
473 
474  //---------------------------------------------------------------------------
479  {
480  assert(m_sOprtChars.size());
481  return m_sOprtChars.c_str();
482  }
483 
484  //---------------------------------------------------------------------------
489  {
490  assert(m_sInfixOprtChars.size());
491  return m_sInfixOprtChars.c_str();
492  }
493 
494  //---------------------------------------------------------------------------
500  bool a_bAllowOpt)
501  {
502  AddCallback(a_sName,
504  m_PostOprtDef,
505  ValidOprtChars() );
506  }
507 
508  //---------------------------------------------------------------------------
514  {
515  InitCharSets();
516  InitFun();
517  InitConst();
518  InitOprt();
519  }
520 
521  //---------------------------------------------------------------------------
531  fun_type1 a_pFun,
532  int a_iPrec,
533  bool a_bAllowOpt)
534  {
535  AddCallback(a_sName,
536  ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX),
539  }
540 
541 
542  //---------------------------------------------------------------------------
552  void ParserBase::DefineOprt( const string_type &a_sName,
553  fun_type2 a_pFun,
554  unsigned a_iPrec,
555  EOprtAssociativity a_eAssociativity,
556  bool a_bAllowOpt )
557  {
558  // Check for conflicts with built in operator names
559  for (int i=0; m_bBuiltInOp && i<cmENDIF; ++i)
560  if (a_sName == string_type(c_DefaultOprt[i]))
561  Error(ecBUILTIN_OVERLOAD, -1, a_sName);
562 
563  AddCallback(a_sName,
564  ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, a_eAssociativity),
565  m_OprtDef,
566  ValidOprtChars() );
567  }
568 
569  //---------------------------------------------------------------------------
574  void ParserBase::DefineStrConst(const string_type &a_strName, const string_type &a_strVal)
575  {
576  // Test if a constant with that names already exists
577  if (m_StrVarDef.find(a_strName)!=m_StrVarDef.end())
579 
580  CheckName(a_strName, ValidNameChars());
581 
582  m_vStringVarBuf.push_back(a_strVal); // Store variable string in internal buffer
583  m_StrVarDef[a_strName] = m_vStringVarBuf.size()-1; // bind buffer index to variable name
584 
585  ReInit();
586  }
587 
588  //---------------------------------------------------------------------------
596  {
597  if (a_pVar==0)
599 
600  // Test if a constant with that names already exists
601  if (m_ConstDef.find(a_sName)!=m_ConstDef.end())
603 
604  CheckName(a_sName, ValidNameChars());
605  m_VarDef[a_sName] = a_pVar;
606  // ReInit();
607  }
608 
609  //---------------------------------------------------------------------------
617  {
618  CheckName(a_sName, ValidNameChars());
619  m_ConstDef[a_sName] = a_fVal;
620  ReInit();
621  }
622 
623  //---------------------------------------------------------------------------
628  {
629  switch (a_Tok.GetCode())
630  {
631  // built in operators
632  case cmEND: return -5;
633  case cmARG_SEP: return -4;
634  case cmASSIGN: return -1;
635  case cmELSE:
636  case cmIF: return 0;
637  case cmLAND: return prLAND;
638  case cmLOR: return prLOR;
639  case cmLT:
640  case cmGT:
641  case cmLE:
642  case cmGE:
643  case cmNEQ:
644  case cmEQ: return prCMP;
645  case cmADD:
646  case cmSUB: return prADD_SUB;
647  case cmMUL:
648  case cmDIV: return prMUL_DIV;
649  case cmPOW: return prPOW;
650 
651  // user defined binary operators
652  case cmOPRT_INFIX:
653  case cmOPRT_BIN: return a_Tok.GetPri();
654  default: Error(ecINTERNAL_ERROR, 5);
655  return 999;
656  }
657  }
658 
659  //---------------------------------------------------------------------------
664  {
665  switch (a_Tok.GetCode())
666  {
667  case cmASSIGN:
668  case cmLAND:
669  case cmLOR:
670  case cmLT:
671  case cmGT:
672  case cmLE:
673  case cmGE:
674  case cmNEQ:
675  case cmEQ:
676  case cmADD:
677  case cmSUB:
678  case cmMUL:
679  case cmDIV: return oaLEFT;
680  case cmPOW: return oaRIGHT;
681  case cmOPRT_BIN: return a_Tok.GetAssociativity();
682  default: return oaNONE;
683  }
684  }
685 
686  //---------------------------------------------------------------------------
689  {
690  try
691  {
692  m_pTokenReader->IgnoreUndefVar(true);
693  CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it
694  // may contain references to nonexisting variables.
696  m_pTokenReader->IgnoreUndefVar(false);
697  }
698  catch(exception_type & /*e*/)
699  {
700  // Make sure to stay in string parse mode, don't call ReInit()
701  // because it deletes the array with the used variables
703  m_pTokenReader->IgnoreUndefVar(false);
704  throw;
705  }
706 
707  return m_pTokenReader->GetUsedVar();
708  }
709 
710  //---------------------------------------------------------------------------
713  {
714  return m_VarDef;
715  }
716 
717  //---------------------------------------------------------------------------
720  {
721  return m_ConstDef;
722  }
723 
724  //---------------------------------------------------------------------------
736  {
737  return m_FunDef;
738  }
739 
740  //---------------------------------------------------------------------------
743  {
744  return m_pTokenReader->GetExpr();
745  }
746 
747  //---------------------------------------------------------------------------
753  const std::vector<token_type> &a_vArg) const
754  {
755  if (a_vArg.back().GetCode()!=cmSTRING)
756  Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
757 
758  token_type valTok;
759  generic_fun_type pFunc = a_FunTok.GetFuncAddr();
760  assert(pFunc);
761 
762  try
763  {
764  // Check function arguments; write dummy value into valtok to represent the result
765  switch(a_FunTok.GetArgCount())
766  {
767  case 0: valTok.SetVal(1); a_vArg[0].GetAsString(); break;
768  case 1: valTok.SetVal(1); a_vArg[1].GetAsString(); a_vArg[0].GetVal(); break;
769  case 2: valTok.SetVal(1); a_vArg[2].GetAsString(); a_vArg[1].GetVal(); a_vArg[0].GetVal(); break;
770  default: Error(ecINTERNAL_ERROR);
771  }
772  }
773  catch(ParserError& )
774  {
775  Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
776  }
777 
778  // string functions won't be optimized
779  m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx());
780 
781  // Push dummy value representing the function result to the stack
782  return valTok;
783  }
784 
785  //---------------------------------------------------------------------------
793  ParserStack<token_type> &a_stVal,
794  int a_iArgCount) const
795  {
796  assert(m_pTokenReader.get());
797 
798  // Operator stack empty or does not contain tokens with callback functions
799  if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr()==0 )
800  return;
801 
802  token_type funTok = a_stOpt.pop();
803  assert(funTok.GetFuncAddr());
804 
805  // Binary operators must rely on their internal operator number
806  // since counting of operators relies on commas for function arguments
807  // binary operators do not have commas in their expression
808  int iArgCount = (funTok.GetCode()==cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount;
809 
810  // determine how many parameters the function needs. To remember iArgCount includes the
811  // string parameter whilst GetArgCount() counts only numeric parameters.
812  int iArgRequired = funTok.GetArgCount() + ((funTok.GetType()==tpSTR) ? 1 : 0);
813 
814  // That's the number of numerical parameters
815  int iArgNumerical = iArgCount - ((funTok.GetType()==tpSTR) ? 1 : 0);
816 
817  if (funTok.GetCode()==cmFUNC_STR && iArgCount-iArgNumerical>1)
819 
820  if (funTok.GetArgCount()>=0 && iArgCount>iArgRequired)
821  Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());
822 
823  if (funTok.GetCode()!=cmOPRT_BIN && iArgCount<iArgRequired )
824  Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());
825 
826  if (funTok.GetCode()==cmFUNC_STR && iArgCount>iArgRequired )
827  Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());
828 
829  // Collect the numeric function arguments from the value stack and store them
830  // in a vector
831  std::vector<token_type> stArg;
832  for (int i=0; i<iArgNumerical; ++i)
833  {
834  stArg.push_back( a_stVal.pop() );
835  if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR )
836  Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
837  }
838 
839  switch(funTok.GetCode())
840  {
841  case cmFUNC_STR:
842  stArg.push_back(a_stVal.pop());
843 
844  if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR )
845  Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
846 
847  ApplyStrFunc(funTok, stArg);
848  break;
849 
850  case cmFUNC_BULK:
851  m_vRPN.AddBulkFun(funTok.GetFuncAddr(), (int)stArg.size());
852  break;
853 
854  case cmOPRT_BIN:
855  case cmOPRT_POSTFIX:
856  case cmOPRT_INFIX:
857  case cmFUNC:
858  if (funTok.GetArgCount()==-1 && iArgCount==0)
859  Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString());
860 
861  m_vRPN.AddFun(funTok.GetFuncAddr(), (funTok.GetArgCount()==-1) ? -iArgNumerical : iArgNumerical);
862  break;
863  default:
864  break;
865  }
866 
867  // Push dummy value representing the function result to the stack
869  token.SetVal(1);
870  a_stVal.push(token);
871  }
872 
873  //---------------------------------------------------------------------------
875  ParserStack<token_type> &a_stVal) const
876  {
877  // Check if there is an if Else clause to be calculated
878  while (a_stOpt.size() && a_stOpt.top().GetCode()==cmELSE)
879  {
880  token_type opElse = a_stOpt.pop();
881  MUP_ASSERT(a_stOpt.size()>0);
882 
883  // Take the value associated with the else branch from the value stack
884  token_type vVal2 = a_stVal.pop();
885 
886  MUP_ASSERT(a_stOpt.size()>0);
887  MUP_ASSERT(a_stVal.size()>=2);
888 
889  // it then else is a ternary operator Pop all three values from the value s
890  // tack and just return the right value
891  token_type vVal1 = a_stVal.pop();
892  token_type vExpr = a_stVal.pop();
893 
894  a_stVal.push( (vExpr.GetVal()!=0) ? vVal1 : vVal2);
895 
896  token_type opIf = a_stOpt.pop();
897  MUP_ASSERT(opElse.GetCode()==cmELSE);
898  MUP_ASSERT(opIf.GetCode()==cmIF);
899 
901  } // while pending if-else-clause found
902  }
903 
904  //---------------------------------------------------------------------------
909  ParserStack<token_type> &a_stVal) const
910  {
911  // is it a user defined binary operator?
912  if (a_stOpt.top().GetCode()==cmOPRT_BIN)
913  {
914  ApplyFunc(a_stOpt, a_stVal, 2);
915  }
916  else
917  {
918  MUP_ASSERT(a_stVal.size()>=2);
919  token_type valTok1 = a_stVal.pop(),
920  valTok2 = a_stVal.pop(),
921  optTok = a_stOpt.pop(),
922  resTok;
923 
924  if ( valTok1.GetType()!=valTok2.GetType() ||
925  (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) )
926  Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString());
927 
928  if (optTok.GetCode()==cmASSIGN)
929  {
930  if (valTok2.GetCode()!=cmVAR)
931  Error(ecUNEXPECTED_OPERATOR, -1, _T("="));
932 
933  m_vRPN.AddAssignOp(valTok2.GetVar());
934  }
935  else
936  m_vRPN.AddOp(optTok.GetCode());
937 
938  resTok.SetVal(1);
939  a_stVal.push(resTok);
940  }
941  }
942 
943  //---------------------------------------------------------------------------
949  ParserStack<token_type> &stVal) const
950  {
951  while (stOpt.size() &&
952  stOpt.top().GetCode() != cmBO &&
953  stOpt.top().GetCode() != cmIF)
954  {
955  token_type tok = stOpt.top();
956  switch (tok.GetCode())
957  {
958  case cmOPRT_INFIX:
959  case cmOPRT_BIN:
960  case cmLE:
961  case cmGE:
962  case cmNEQ:
963  case cmEQ:
964  case cmLT:
965  case cmGT:
966  case cmADD:
967  case cmSUB:
968  case cmMUL:
969  case cmDIV:
970  case cmPOW:
971  case cmLAND:
972  case cmLOR:
973  case cmASSIGN:
974  if (stOpt.top().GetCode()==cmOPRT_INFIX)
975  ApplyFunc(stOpt, stVal, 1);
976  else
977  ApplyBinOprt(stOpt, stVal);
978  break;
979 
980  case cmELSE:
981  ApplyIfElse(stOpt, stVal);
982  break;
983 
984  default:
986  }
987  }
988  }
989 
990  //---------------------------------------------------------------------------
999  {
1000  return ParseCmdCodeBulk(0, 0);
1001  }
1002 
1003  //---------------------------------------------------------------------------
1008  value_type ParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const
1009  {
1010  assert(nThreadID<=s_MaxNumOpenMPThreads);
1011 
1012  // Note: The check for nOffset==0 and nThreadID here is not necessary but
1013  // brings a minor performance gain when not in bulk mode.
1014  value_type *Stack = ((nOffset==0) && (nThreadID==0)) ? &m_vStackBuffer[0] : &m_vStackBuffer[nThreadID * (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)];
1015  value_type buf;
1016  int sidx(0);
1017  for (const SToken *pTok = m_vRPN.GetBase(); pTok->Cmd!=cmEND ; ++pTok)
1018  {
1019  switch (pTok->Cmd)
1020  {
1021  // built in binary operators
1022  case cmLE: --sidx; Stack[sidx] = Stack[sidx] <= Stack[sidx+1]; continue;
1023  case cmGE: --sidx; Stack[sidx] = Stack[sidx] >= Stack[sidx+1]; continue;
1024  case cmNEQ: --sidx; Stack[sidx] = Stack[sidx] != Stack[sidx+1]; continue;
1025  case cmEQ: --sidx; Stack[sidx] = Stack[sidx] == Stack[sidx+1]; continue;
1026  case cmLT: --sidx; Stack[sidx] = Stack[sidx] < Stack[sidx+1]; continue;
1027  case cmGT: --sidx; Stack[sidx] = Stack[sidx] > Stack[sidx+1]; continue;
1028  case cmADD: --sidx; Stack[sidx] += Stack[1+sidx]; continue;
1029  case cmSUB: --sidx; Stack[sidx] -= Stack[1+sidx]; continue;
1030  case cmMUL: --sidx; Stack[sidx] *= Stack[1+sidx]; continue;
1031  case cmDIV: --sidx;
1032 
1033  #if defined(MUP_MATH_EXCEPTIONS)
1034  if (Stack[1+sidx]==0)
1036  #endif
1037  Stack[sidx] /= Stack[1+sidx];
1038  continue;
1039 
1040  case cmPOW:
1041  --sidx; Stack[sidx] = MathImpl<value_type>::Pow(Stack[sidx], Stack[1+sidx]);
1042  continue;
1043 
1044  case cmLAND: --sidx; Stack[sidx] = Stack[sidx] && Stack[sidx+1]; continue;
1045  case cmLOR: --sidx; Stack[sidx] = Stack[sidx] || Stack[sidx+1]; continue;
1046 
1047  case cmASSIGN:
1048  // Bugfix for Bulkmode:
1049  // for details see:
1050  // 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
1051  --sidx; Stack[sidx] = *(pTok->Oprt.ptr + nOffset) = Stack[sidx + 1]; continue;
1052  // original code:
1053  //--sidx; Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; continue;
1054 
1055  //case cmBO: // unused, listed for compiler optimization purposes
1056  //case cmBC:
1057  // MUP_FAIL(INVALID_CODE_IN_BYTECODE);
1058  // continue;
1059 
1060  case cmIF:
1061  if (Stack[sidx--]==0)
1062  pTok += pTok->Oprt.offset;
1063  continue;
1064 
1065  case cmELSE:
1066  pTok += pTok->Oprt.offset;
1067  continue;
1068 
1069  case cmENDIF:
1070  continue;
1071 
1072  //case cmARG_SEP:
1073  // MUP_FAIL(INVALID_CODE_IN_BYTECODE);
1074  // continue;
1075 
1076  // value and variable tokens
1077  case cmVAR: Stack[++sidx] = *(pTok->Val.ptr + nOffset); continue;
1078  case cmVAL: Stack[++sidx] = pTok->Val.data2; continue;
1079 
1080  case cmVARPOW2: buf = *(pTok->Val.ptr + nOffset);
1081  Stack[++sidx] = buf*buf;
1082  continue;
1083 
1084  case cmVARPOW3: buf = *(pTok->Val.ptr + nOffset);
1085  Stack[++sidx] = buf*buf*buf;
1086  continue;
1087 
1088  case cmVARPOW4: buf = *(pTok->Val.ptr + nOffset);
1089  Stack[++sidx] = buf*buf*buf*buf;
1090  continue;
1091 
1092  case cmVARMUL: Stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2;
1093  continue;
1094 
1095  // Next is treatment of numeric functions
1096  case cmFUNC:
1097  {
1098  int iArgCount = pTok->Fun.argc;
1099 
1100  // switch according to argument count
1101  switch(iArgCount)
1102  {
1103  case 0: sidx += 1; Stack[sidx] = (*(fun_type0)pTok->Fun.ptr)(); continue;
1104  case 1: Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(Stack[sidx]); continue;
1105  case 2: sidx -= 1; Stack[sidx] = (*(fun_type2)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1]); continue;
1106  case 3: sidx -= 2; Stack[sidx] = (*(fun_type3)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue;
1107  case 4: sidx -= 3; Stack[sidx] = (*(fun_type4)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue;
1108  case 5: sidx -= 4; Stack[sidx] = (*(fun_type5)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue;
1109  case 6: sidx -= 5; Stack[sidx] = (*(fun_type6)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue;
1110  case 7: sidx -= 6; Stack[sidx] = (*(fun_type7)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); continue;
1111  case 8: sidx -= 7; Stack[sidx] = (*(fun_type8)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); continue;
1112  case 9: sidx -= 8; Stack[sidx] = (*(fun_type9)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); continue;
1113  case 10:sidx -= 9; Stack[sidx] = (*(fun_type10)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); continue;
1114  default:
1115  if (iArgCount>0) // function with variable arguments store the number as a negative value
1116  Error(ecINTERNAL_ERROR, 1);
1117 
1118  sidx -= -iArgCount - 1;
1119  Stack[sidx] =(*(multfun_type)pTok->Fun.ptr)(&Stack[sidx], -iArgCount);
1120  continue;
1121  }
1122  }
1123 
1124  // Next is treatment of string functions
1125  case cmFUNC_STR:
1126  {
1127  sidx -= pTok->Fun.argc -1;
1128 
1129  // The index of the string argument in the string table
1130  int iIdxStack = pTok->Fun.idx;
1131  MUP_ASSERT( iIdxStack>=0 && iIdxStack<(int)m_vStringBuf.size() );
1132 
1133  switch(pTok->Fun.argc) // switch according to argument count
1134  {
1135  case 0: Stack[sidx] = (*(strfun_type1)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str()); continue;
1136  case 1: Stack[sidx] = (*(strfun_type2)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx]); continue;
1137  case 2: Stack[sidx] = (*(strfun_type3)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx+1]); continue;
1138  }
1139 
1140  continue;
1141  }
1142 
1143  case cmFUNC_BULK:
1144  {
1145  int iArgCount = pTok->Fun.argc;
1146 
1147  // switch according to argument count
1148  switch(iArgCount)
1149  {
1150  case 0: sidx += 1; Stack[sidx] = (*(bulkfun_type0 )pTok->Fun.ptr)(nOffset, nThreadID); continue;
1151  case 1: Stack[sidx] = (*(bulkfun_type1 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx]); continue;
1152  case 2: sidx -= 1; Stack[sidx] = (*(bulkfun_type2 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1]); continue;
1153  case 3: sidx -= 2; Stack[sidx] = (*(bulkfun_type3 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue;
1154  case 4: sidx -= 3; Stack[sidx] = (*(bulkfun_type4 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue;
1155  case 5: sidx -= 4; Stack[sidx] = (*(bulkfun_type5 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue;
1156  case 6: sidx -= 5; Stack[sidx] = (*(bulkfun_type6 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue;
1157  case 7: sidx -= 6; Stack[sidx] = (*(bulkfun_type7 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); continue;
1158  case 8: sidx -= 7; Stack[sidx] = (*(bulkfun_type8 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); continue;
1159  case 9: sidx -= 8; Stack[sidx] = (*(bulkfun_type9 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); continue;
1160  case 10:sidx -= 9; Stack[sidx] = (*(bulkfun_type10)pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); continue;
1161  default:
1162  Error(ecINTERNAL_ERROR, 2);
1163  continue;
1164  }
1165  }
1166 
1167  default:
1168  Error(ecINTERNAL_ERROR, 3);
1169  return 0;
1170  } // switch CmdCode
1171  } // for all bytecode tokens
1172 
1173  return Stack[m_nFinalResultIdx];
1174  }
1175 
1176  //---------------------------------------------------------------------------
1177  void ParserBase::CreateRPN() const
1178  {
1179  if (!m_pTokenReader->GetExpr().length())
1180  Error(ecUNEXPECTED_EOF, 0);
1181 
1182  ParserStack<token_type> stOpt, stVal;
1183  ParserStack<int> stArgCount;
1184  token_type opta, opt; // for storing operators
1185  token_type val, tval; // for storing value
1186 
1187  ReInit();
1188 
1189  // The outermost counter counts the number of separated items
1190  // such as in "a=10,b=20,c=c+a"
1191  stArgCount.push(1);
1192 
1193  for(;;)
1194  {
1195  opt = m_pTokenReader->ReadNextToken();
1196 
1197  switch (opt.GetCode())
1198  {
1199  //
1200  // Next three are different kind of value entries
1201  //
1202  case cmSTRING:
1203  opt.SetIdx((int)m_vStringBuf.size()); // Assign buffer index to token
1204  stVal.push(opt);
1205  m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer
1206  break;
1207 
1208  case cmVAR:
1209  stVal.push(opt);
1210  m_vRPN.AddVar( static_cast<value_type*>(opt.GetVar()) );
1211  break;
1212 
1213  case cmVAL:
1214  stVal.push(opt);
1215  m_vRPN.AddVal( opt.GetVal() );
1216  break;
1217 
1218  case cmELSE:
1219  m_nIfElseCounter--;
1220  if (m_nIfElseCounter<0)
1221  Error(ecMISPLACED_COLON, m_pTokenReader->GetPos());
1222 
1223  ApplyRemainingOprt(stOpt, stVal);
1224  m_vRPN.AddIfElse(cmELSE);
1225  stOpt.push(opt);
1226  break;
1227 
1228 
1229  case cmARG_SEP:
1230  if (stArgCount.empty())
1231  Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos());
1232 
1233  ++stArgCount.top();
1234  // Falls through.
1235  // intentional (no break!)
1236 
1237  case cmEND:
1238  ApplyRemainingOprt(stOpt, stVal);
1239  break;
1240 
1241  case cmBC:
1242  {
1243  // The argument count for parameterless functions is zero
1244  // by default an opening bracket sets parameter count to 1
1245  // in preparation of arguments to come. If the last token
1246  // was an opening bracket we know better...
1247  if (opta.GetCode()==cmBO)
1248  --stArgCount.top();
1249 
1250  ApplyRemainingOprt(stOpt, stVal);
1251 
1252  // Check if the bracket content has been evaluated completely
1253  if (stOpt.size() && stOpt.top().GetCode()==cmBO)
1254  {
1255  // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check
1256  // if there is either a function or a sign pending
1257  // neither the opening nor the closing bracket will be pushed back to
1258  // the operator stack
1259  // Check if a function is standing in front of the opening bracket,
1260  // if yes evaluate it afterwards check for infix operators
1261  assert(stArgCount.size());
1262  int iArgCount = stArgCount.pop();
1263 
1264  stOpt.pop(); // Take opening bracket from stack
1265 
1266  if (iArgCount>1 && ( stOpt.size()==0 ||
1267  (stOpt.top().GetCode()!=cmFUNC &&
1268  stOpt.top().GetCode()!=cmFUNC_BULK &&
1269  stOpt.top().GetCode()!=cmFUNC_STR) ) )
1270  Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos());
1271 
1272  // The opening bracket was popped from the stack now check if there
1273  // was a function before this bracket
1274  if (stOpt.size() &&
1275  stOpt.top().GetCode()!=cmOPRT_INFIX &&
1276  stOpt.top().GetCode()!=cmOPRT_BIN &&
1277  stOpt.top().GetFuncAddr()!=0)
1278  {
1279  ApplyFunc(stOpt, stVal, iArgCount);
1280  }
1281  }
1282  } // if bracket content is evaluated
1283  break;
1284 
1285  //
1286  // Next are the binary operator entries
1287  //
1288  //case cmAND: // built in binary operators
1289  //case cmOR:
1290  //case cmXOR:
1291  case cmIF:
1292  m_nIfElseCounter++;
1293  // Falls through.
1294  // intentional (no break!)
1295 
1296  case cmLAND:
1297  case cmLOR:
1298  case cmLT:
1299  case cmGT:
1300  case cmLE:
1301  case cmGE:
1302  case cmNEQ:
1303  case cmEQ:
1304  case cmADD:
1305  case cmSUB:
1306  case cmMUL:
1307  case cmDIV:
1308  case cmPOW:
1309  case cmASSIGN:
1310  case cmOPRT_BIN:
1311 
1312  // A binary operator (user defined or built in) has been found.
1313  while ( stOpt.size() &&
1314  stOpt.top().GetCode() != cmBO &&
1315  stOpt.top().GetCode() != cmELSE &&
1316  stOpt.top().GetCode() != cmIF)
1317  {
1318  int nPrec1 = GetOprtPrecedence(stOpt.top()),
1319  nPrec2 = GetOprtPrecedence(opt);
1320 
1321  if (stOpt.top().GetCode()==opt.GetCode())
1322  {
1323 
1324  // Deal with operator associativity
1325  EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt);
1326  if ( (eOprtAsct==oaRIGHT && (nPrec1 <= nPrec2)) ||
1327  (eOprtAsct==oaLEFT && (nPrec1 < nPrec2)) )
1328  {
1329  break;
1330  }
1331  }
1332  else if (nPrec1 < nPrec2)
1333  {
1334  // In case the operators are not equal the precedence decides alone...
1335  break;
1336  }
1337 
1338  if (stOpt.top().GetCode()==cmOPRT_INFIX)
1339  ApplyFunc(stOpt, stVal, 1);
1340  else
1341  ApplyBinOprt(stOpt, stVal);
1342  } // while ( ... )
1343 
1344  if (opt.GetCode()==cmIF)
1345  m_vRPN.AddIfElse(opt.GetCode());
1346 
1347  // The operator can't be evaluated right now, push back to the operator stack
1348  stOpt.push(opt);
1349  break;
1350 
1351  //
1352  // Last section contains functions and operators implicitly mapped to functions
1353  //
1354  case cmBO:
1355  stArgCount.push(1);
1356  stOpt.push(opt);
1357  break;
1358 
1359  case cmOPRT_INFIX:
1360  case cmFUNC:
1361  case cmFUNC_BULK:
1362  case cmFUNC_STR:
1363  stOpt.push(opt);
1364  break;
1365 
1366  case cmOPRT_POSTFIX:
1367  stOpt.push(opt);
1368  ApplyFunc(stOpt, stVal, 1); // this is the postfix operator
1369  break;
1370 
1371  default: Error(ecINTERNAL_ERROR, 3);
1372  } // end of switch operator-token
1373 
1374  opta = opt;
1375 
1376  if ( opt.GetCode() == cmEND )
1377  {
1378  m_vRPN.Finalize();
1379  break;
1380  }
1381 
1382  if (ParserBase::g_DbgDumpStack)
1383  {
1384  StackDump(stVal, stOpt);
1385  m_vRPN.AsciiDump();
1386  }
1387  } // while (true)
1388 
1389  if (ParserBase::g_DbgDumpCmdCode)
1390  m_vRPN.AsciiDump();
1391 
1392  if (m_nIfElseCounter>0)
1393  Error(ecMISSING_ELSE_CLAUSE);
1394 
1395  // get the last value (= final result) from the stack
1396  MUP_ASSERT(stArgCount.size()==1);
1397  m_nFinalResultIdx = stArgCount.top();
1398  if (m_nFinalResultIdx==0)
1399  Error(ecINTERNAL_ERROR, 9);
1400 
1401  if (stVal.size()==0)
1402  Error(ecEMPTY_EXPRESSION);
1403 
1404  if (stVal.top().GetType()!=tpDBL)
1405  Error(ecSTR_RESULT);
1406 
1407  m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads);
1408  }
1409 
1410  //---------------------------------------------------------------------------
1419  value_type ParserBase::ParseString() const
1420  {
1421  try
1422  {
1423  CreateRPN();
1424  m_pParseFormula = &ParserBase::ParseCmdCode;
1425  return (this->*m_pParseFormula)();
1426  }
1427  catch(ParserError &exc)
1428  {
1429  exc.SetFormula(m_pTokenReader->GetExpr());
1430  throw;
1431  }
1432  }
1433 
1434  //---------------------------------------------------------------------------
1445  void ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const
1446  {
1447  throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos);
1448  }
1449 
1450  //------------------------------------------------------------------------------
1456  void ParserBase::ClearVar()
1457  {
1458  m_VarDef.clear();
1459  ReInit();
1460  }
1461 
1462  //------------------------------------------------------------------------------
1468  void ParserBase::RemoveVar(const string_type &a_strVarName)
1469  {
1470  varmap_type::iterator item = m_VarDef.find(a_strVarName);
1471  if (item!=m_VarDef.end())
1472  {
1473  m_VarDef.erase(item);
1474  ReInit();
1475  }
1476  }
1477 
1478  //------------------------------------------------------------------------------
1483  void ParserBase::ClearFun()
1484  {
1485  m_FunDef.clear();
1486  ReInit();
1487  }
1488 
1489  //------------------------------------------------------------------------------
1496  void ParserBase::ClearConst()
1497  {
1498  m_ConstDef.clear();
1499  m_StrVarDef.clear();
1500  ReInit();
1501  }
1502 
1503  //------------------------------------------------------------------------------
1508  void ParserBase::ClearPostfixOprt()
1509  {
1510  m_PostOprtDef.clear();
1511  ReInit();
1512  }
1513 
1514  //------------------------------------------------------------------------------
1519  void ParserBase::ClearOprt()
1520  {
1521  m_OprtDef.clear();
1522  ReInit();
1523  }
1524 
1525  //------------------------------------------------------------------------------
1530  void ParserBase::ClearInfixOprt()
1531  {
1532  m_InfixOprtDef.clear();
1533  ReInit();
1534  }
1535 
1536  //------------------------------------------------------------------------------
1541  void ParserBase::EnableOptimizer(bool a_bIsOn)
1542  {
1543  m_vRPN.EnableOptimizer(a_bIsOn);
1544  ReInit();
1545  }
1546 
1547  //---------------------------------------------------------------------------
1554  void ParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack)
1555  {
1556  ParserBase::g_DbgDumpCmdCode = bDumpCmd;
1557  ParserBase::g_DbgDumpStack = bDumpStack;
1558  }
1559 
1560  //------------------------------------------------------------------------------
1570  void ParserBase::EnableBuiltInOprt(bool a_bIsOn)
1571  {
1572  m_bBuiltInOp = a_bIsOn;
1573  ReInit();
1574  }
1575 
1576  //------------------------------------------------------------------------------
1581  bool ParserBase::HasBuiltInOprt() const
1582  {
1583  return m_bBuiltInOp;
1584  }
1585 
1586  //------------------------------------------------------------------------------
1589  char_type ParserBase::GetArgSep() const
1590  {
1591  return m_pTokenReader->GetArgSep();
1592  }
1593 
1594  //------------------------------------------------------------------------------
1598  void ParserBase::SetArgSep(char_type cArgSep)
1599  {
1600  m_pTokenReader->SetArgSep(cArgSep);
1601  }
1602 
1603  //------------------------------------------------------------------------------
1608  void ParserBase::StackDump(const ParserStack<token_type> &a_stVal,
1609  const ParserStack<token_type> &a_stOprt) const
1610  {
1611  ParserStack<token_type> stOprt(a_stOprt),
1612  stVal(a_stVal);
1613 
1614  mu::console() << _T("\nValue stack:\n");
1615  while ( !stVal.empty() )
1616  {
1617  token_type val = stVal.pop();
1618  if (val.GetType()==tpSTR)
1619  mu::console() << _T(" \"") << val.GetAsString() << _T("\" ");
1620  else
1621  mu::console() << _T(" ") << val.GetVal() << _T(" ");
1622  }
1623  mu::console() << "\nOperator stack:\n";
1624 
1625  while ( !stOprt.empty() )
1626  {
1627  if (stOprt.top().GetCode()<=cmASSIGN)
1628  {
1629  mu::console() << _T("OPRT_INTRNL \"")
1630  << ParserBase::c_DefaultOprt[stOprt.top().GetCode()]
1631  << _T("\" \n");
1632  }
1633  else
1634  {
1635  switch(stOprt.top().GetCode())
1636  {
1637  case cmVAR: mu::console() << _T("VAR\n"); break;
1638  case cmVAL: mu::console() << _T("VAL\n"); break;
1639  case cmFUNC: mu::console() << _T("FUNC \"")
1640  << stOprt.top().GetAsString()
1641  << _T("\"\n"); break;
1642  case cmFUNC_BULK: mu::console() << _T("FUNC_BULK \"")
1643  << stOprt.top().GetAsString()
1644  << _T("\"\n"); break;
1645  case cmOPRT_INFIX: mu::console() << _T("OPRT_INFIX \"")
1646  << stOprt.top().GetAsString()
1647  << _T("\"\n"); break;
1648  case cmOPRT_BIN: mu::console() << _T("OPRT_BIN \"")
1649  << stOprt.top().GetAsString()
1650  << _T("\"\n"); break;
1651  case cmFUNC_STR: mu::console() << _T("FUNC_STR\n"); break;
1652  case cmEND: mu::console() << _T("END\n"); break;
1653  case cmUNKNOWN: mu::console() << _T("UNKNOWN\n"); break;
1654  case cmBO: mu::console() << _T("BRACKET \"(\"\n"); break;
1655  case cmBC: mu::console() << _T("BRACKET \")\"\n"); break;
1656  case cmIF: mu::console() << _T("IF\n"); break;
1657  case cmELSE: mu::console() << _T("ELSE\n"); break;
1658  case cmENDIF: mu::console() << _T("ENDIF\n"); break;
1659  default: mu::console() << stOprt.top().GetCode() << _T(" "); break;
1660  }
1661  }
1662  stOprt.pop();
1663  }
1664 
1665  mu::console() << dec << endl;
1666  }
1667 
1668  //------------------------------------------------------------------------------
1676  value_type* ParserBase::Eval(int &nStackSize) const
1677  {
1678  (this->*m_pParseFormula)();
1679  nStackSize = m_nFinalResultIdx;
1680 
1681  // (for historic reasons the stack starts at position 1)
1682  return &m_vStackBuffer[1];
1683  }
1684 
1685  //---------------------------------------------------------------------------
1692  int ParserBase::GetNumResults() const
1693  {
1694  return m_nFinalResultIdx;
1695  }
1696 
1697  //---------------------------------------------------------------------------
1713  value_type ParserBase::Eval() const
1714  {
1715  return (this->*m_pParseFormula)();
1716  }
1717 
1718  //---------------------------------------------------------------------------
1719  void ParserBase::Eval(value_type *results, int nBulkSize)
1720  {
1721 /* <ibg 2014-09-24/> Commented because it is making a unit test impossible
1722 
1723  // Parallelization does not make sense for fewer than 10000 computations
1724  // due to thread creation overhead. If the bulk size is below 2000
1725  // computation is refused.
1726  if (nBulkSize<2000)
1727  {
1728  throw ParserError(ecUNREASONABLE_NUMBER_OF_COMPUTATIONS);
1729  }
1730 */
1731  CreateRPN();
1732 
1733  int i = 0;
1734 
1735 #ifdef MUP_USE_OPENMP
1736 //#define DEBUG_OMP_STUFF
1737  #ifdef DEBUG_OMP_STUFF
1738  int *pThread = new int[nBulkSize];
1739  int *pIdx = new int[nBulkSize];
1740  #endif
1741 
1742  int nMaxThreads = std::min(omp_get_max_threads(), s_MaxNumOpenMPThreads);
1743  int nThreadID = 0, ct = 0;
1744  omp_set_num_threads(nMaxThreads);
1745 
1746  #pragma omp parallel for schedule(static, nBulkSize/nMaxThreads) private(nThreadID)
1747  for (i=0; i<nBulkSize; ++i)
1748  {
1749  nThreadID = omp_get_thread_num();
1750  results[i] = ParseCmdCodeBulk(i, nThreadID);
1751 
1752  #ifdef DEBUG_OMP_STUFF
1753  #pragma omp critical
1754  {
1755  pThread[ct] = nThreadID;
1756  pIdx[ct] = i;
1757  ct++;
1758  }
1759  #endif
1760  }
1761 
1762 #ifdef DEBUG_OMP_STUFF
1763  FILE *pFile = fopen("bulk_dbg.txt", "w");
1764  for (i=0; i<nBulkSize; ++i)
1765  {
1766  fprintf(pFile, "idx: %d thread: %d \n", pIdx[i], pThread[i]);
1767  }
1768 
1769  delete [] pIdx;
1770  delete [] pThread;
1771 
1772  fclose(pFile);
1773 #endif
1774 
1775 #else
1776  for (i=0; i<nBulkSize; ++i)
1777  {
1778  results[i] = ParseCmdCodeBulk(i, 0);
1779  }
1780 #endif
1781 
1782  }
1783 } // namespace mu