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