1 /* 2 __________ 3 _____ __ __\______ \_____ _______ ______ ____ _______ 4 / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ 5 | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ 6 |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| 7 \/ \/ \/ \/ 8 Copyright (C) 2013 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 #include <cassert> 26 #include <cstdio> 27 #include <cstring> 28 #include <map> 29 #include <stack> 30 #include <string> 31 #include <memory> 32 33 #include "muParserTokenReader.h" 34 #include "muParserBase.h" 35 36 /** \file 37 \brief This file contains the parser token reader implementation. 38 */ 39 40 41 namespace mu 42 { 43 44 // Forward declaration 45 class ParserBase; 46 47 //--------------------------------------------------------------------------- 48 /** \brief Copy constructor. 49 50 \sa Assign 51 \throw nothrow 52 */ ParserTokenReader(const ParserTokenReader & a_Reader)53 ParserTokenReader::ParserTokenReader(const ParserTokenReader &a_Reader) 54 { 55 Assign(a_Reader); 56 } 57 58 //--------------------------------------------------------------------------- 59 /** \brief Assignment operator. 60 61 Self assignment will be suppressed otherwise #Assign is called. 62 63 \param a_Reader Object to copy to this token reader. 64 \throw nothrow 65 */ operator =(const ParserTokenReader & a_Reader)66 ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader &a_Reader) 67 { 68 if (&a_Reader!=this) 69 Assign(a_Reader); 70 71 return *this; 72 } 73 74 //--------------------------------------------------------------------------- 75 /** \brief Assign state of a token reader to this token reader. 76 77 \param a_Reader Object from which the state should be copied. 78 \throw nothrow 79 */ Assign(const ParserTokenReader & a_Reader)80 void ParserTokenReader::Assign(const ParserTokenReader &a_Reader) 81 { 82 m_pParser = a_Reader.m_pParser; 83 m_strFormula = a_Reader.m_strFormula; 84 m_iPos = a_Reader.m_iPos; 85 m_iSynFlags = a_Reader.m_iSynFlags; 86 87 m_UsedVar = a_Reader.m_UsedVar; 88 m_pFunDef = a_Reader.m_pFunDef; 89 m_pConstDef = a_Reader.m_pConstDef; 90 m_pVarDef = a_Reader.m_pVarDef; 91 m_pStrVarDef = a_Reader.m_pStrVarDef; 92 m_pPostOprtDef = a_Reader.m_pPostOprtDef; 93 m_pInfixOprtDef = a_Reader.m_pInfixOprtDef; 94 m_pOprtDef = a_Reader.m_pOprtDef; 95 m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar; 96 m_vIdentFun = a_Reader.m_vIdentFun; 97 m_pFactory = a_Reader.m_pFactory; 98 m_pFactoryData = a_Reader.m_pFactoryData; 99 m_iBrackets = a_Reader.m_iBrackets; 100 m_cArgSep = a_Reader.m_cArgSep; 101 m_fZero = a_Reader.m_fZero; 102 m_lastTok = a_Reader.m_lastTok; 103 } 104 105 //--------------------------------------------------------------------------- 106 /** \brief Constructor. 107 108 Create a Token reader and bind it to a parser object. 109 110 \pre [assert] a_pParser may not be NULL 111 \post #m_pParser==a_pParser 112 \param a_pParent Parent parser object of the token reader. 113 */ ParserTokenReader(ParserBase * a_pParent)114 ParserTokenReader::ParserTokenReader(ParserBase *a_pParent) 115 :m_pParser(a_pParent) 116 ,m_strFormula() 117 ,m_iPos(0) 118 ,m_iSynFlags(0) 119 ,m_bIgnoreUndefVar(false) 120 ,m_pFunDef(NULL) 121 ,m_pPostOprtDef(NULL) 122 ,m_pInfixOprtDef(NULL) 123 ,m_pOprtDef(NULL) 124 ,m_pConstDef(NULL) 125 ,m_pStrVarDef(NULL) 126 ,m_pVarDef(NULL) 127 ,m_pFactory(NULL) 128 ,m_pFactoryData(NULL) 129 ,m_vIdentFun() 130 ,m_UsedVar() 131 ,m_fZero(0) 132 ,m_iBrackets(0) 133 ,m_lastTok() 134 ,m_cArgSep(',') 135 { 136 assert(m_pParser); 137 SetParent(m_pParser); 138 } 139 140 //--------------------------------------------------------------------------- 141 /** \brief Create instance of a ParserTokenReader identical with this 142 and return its pointer. 143 144 This is a factory method the calling function must take care of the object destruction. 145 146 \return A new ParserTokenReader object. 147 \throw nothrow 148 */ Clone(ParserBase * a_pParent) const149 ParserTokenReader* ParserTokenReader::Clone(ParserBase *a_pParent) const 150 { 151 std::unique_ptr<ParserTokenReader> ptr(new ParserTokenReader(*this)); 152 ptr->SetParent(a_pParent); 153 return ptr.release(); 154 } 155 156 //--------------------------------------------------------------------------- SaveBeforeReturn(const token_type & tok)157 ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type &tok) 158 { 159 m_lastTok = tok; 160 return m_lastTok; 161 } 162 163 //--------------------------------------------------------------------------- AddValIdent(identfun_type a_pCallback)164 void ParserTokenReader::AddValIdent(identfun_type a_pCallback) 165 { 166 // Use push_front is used to give user defined callbacks a higher priority than 167 // the built in ones. Otherwise reading hex numbers would not work 168 // since the "0" in "0xff" would always be read first making parsing of 169 // the rest impossible. 170 // reference: 171 // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956 172 m_vIdentFun.push_front(a_pCallback); 173 } 174 175 //--------------------------------------------------------------------------- SetVarCreator(facfun_type a_pFactory,void * pUserData)176 void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void *pUserData) 177 { 178 m_pFactory = a_pFactory; 179 m_pFactoryData = pUserData; 180 } 181 182 //--------------------------------------------------------------------------- 183 /** \brief Return the current position of the token reader in the formula string. 184 185 \return #m_iPos 186 \throw nothrow 187 */ GetPos() const188 int ParserTokenReader::GetPos() const 189 { 190 return m_iPos; 191 } 192 193 //--------------------------------------------------------------------------- 194 /** \brief Return a reference to the formula. 195 196 \return #m_strFormula 197 \throw nothrow 198 */ GetExpr() const199 const string_type& ParserTokenReader::GetExpr() const 200 { 201 return m_strFormula; 202 } 203 204 //--------------------------------------------------------------------------- 205 /** \brief Return a map containing the used variables only. */ GetUsedVar()206 varmap_type& ParserTokenReader::GetUsedVar() 207 { 208 return m_UsedVar; 209 } 210 211 //--------------------------------------------------------------------------- 212 /** \brief Initialize the token Reader. 213 214 Sets the formula position index to zero and set Syntax flags to default for initial formula parsing. 215 \pre [assert] triggered if a_szFormula==0 216 */ SetFormula(const string_type & a_strFormula)217 void ParserTokenReader::SetFormula(const string_type &a_strFormula) 218 { 219 m_strFormula = a_strFormula; 220 ReInit(); 221 } 222 223 //--------------------------------------------------------------------------- 224 /** \brief Set Flag that controls behavior in case of undefined variables being found. 225 226 If true, the parser does not throw an exception if an undefined variable is found. 227 otherwise it does. This variable is used internally only! 228 It suppresses a "undefined variable" exception in GetUsedVar(). 229 Those function should return a complete list of variables including 230 those that are not defined by the time of its call. 231 */ IgnoreUndefVar(bool bIgnore)232 void ParserTokenReader::IgnoreUndefVar(bool bIgnore) 233 { 234 m_bIgnoreUndefVar = bIgnore; 235 } 236 237 //--------------------------------------------------------------------------- 238 /** \brief Reset the token reader to the start of the formula. 239 240 The syntax flags will be reset to a value appropriate for the 241 start of a formula. 242 \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR 243 \throw nothrow 244 \sa ESynCodes 245 */ ReInit()246 void ParserTokenReader::ReInit() 247 { 248 m_iPos = 0; 249 m_iSynFlags = sfSTART_OF_LINE; 250 m_iBrackets = 0; 251 m_UsedVar.clear(); 252 m_lastTok = token_type(); 253 } 254 255 //--------------------------------------------------------------------------- 256 /** \brief Read the next token from the string. */ ReadNextToken()257 ParserTokenReader::token_type ParserTokenReader::ReadNextToken() 258 { 259 assert(m_pParser); 260 261 const char_type *szFormula = m_strFormula.c_str(); 262 token_type tok; 263 264 // Ignore all non printable characters when reading the expression 265 while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20) 266 ++m_iPos; 267 268 if ( IsEOF(tok) ) return SaveBeforeReturn(tok); // Check for end of formula 269 if ( IsOprt(tok) ) return SaveBeforeReturn(tok); // Check for user defined binary operator 270 if ( IsFunTok(tok) ) return SaveBeforeReturn(tok); // Check for function token 271 if ( IsBuiltIn(tok) ) return SaveBeforeReturn(tok); // Check built in operators / tokens 272 if ( IsArgSep(tok) ) return SaveBeforeReturn(tok); // Check for function argument separators 273 if ( IsValTok(tok) ) return SaveBeforeReturn(tok); // Check for values / constant tokens 274 if ( IsVarTok(tok) ) return SaveBeforeReturn(tok); // Check for variable tokens 275 if ( IsStrVarTok(tok) ) return SaveBeforeReturn(tok); // Check for string variables 276 if ( IsString(tok) ) return SaveBeforeReturn(tok); // Check for String tokens 277 if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators 278 if ( IsPostOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators 279 280 // Check String for undefined variable token. Done only if a 281 // flag is set indicating to ignore undefined variables. 282 // This is a way to conditionally avoid an error if 283 // undefined variables occur. 284 // (The GetUsedVar function must suppress the error for 285 // undefined variables in order to collect all variable 286 // names including the undefined ones.) 287 if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) ) 288 return SaveBeforeReturn(tok); 289 290 // Check for unknown token 291 // 292 // !!! From this point on there is no exit without an exception possible... 293 // 294 string_type strTok; 295 int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); 296 if (iEnd!=m_iPos) 297 Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok); 298 299 Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos)); 300 return token_type(); // never reached 301 } 302 303 //--------------------------------------------------------------------------- SetParent(ParserBase * a_pParent)304 void ParserTokenReader::SetParent(ParserBase *a_pParent) 305 { 306 m_pParser = a_pParent; 307 m_pFunDef = &a_pParent->m_FunDef; 308 m_pOprtDef = &a_pParent->m_OprtDef; 309 m_pInfixOprtDef = &a_pParent->m_InfixOprtDef; 310 m_pPostOprtDef = &a_pParent->m_PostOprtDef; 311 m_pVarDef = &a_pParent->m_VarDef; 312 m_pStrVarDef = &a_pParent->m_StrVarDef; 313 m_pConstDef = &a_pParent->m_ConstDef; 314 } 315 316 //--------------------------------------------------------------------------- 317 /** \brief Extract all characters that belong to a certain charset. 318 319 \param a_szCharSet [in] Const char array of the characters allowed in the token. 320 \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet. 321 \param a_iPos [in] Position in the string from where to start reading. 322 \return The Position of the first character not listed in a_szCharSet. 323 \throw nothrow 324 */ ExtractToken(const char_type * a_szCharSet,string_type & a_sTok,int a_iPos) const325 int ParserTokenReader::ExtractToken(const char_type *a_szCharSet, 326 string_type &a_sTok, 327 int a_iPos) const 328 { 329 int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos); 330 331 if (iEnd==(int)string_type::npos) 332 iEnd = (int)m_strFormula.length(); 333 334 // Assign token string if there was something found 335 if (a_iPos!=iEnd) 336 a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd); 337 338 return iEnd; 339 } 340 341 //--------------------------------------------------------------------------- 342 /** \brief Check Expression for the presence of a binary operator token. 343 344 Userdefined binary operator "++" gives inconsistent parsing result for 345 the equations "a++b" and "a ++ b" if alphabetic characters are allowed 346 in operator tokens. To avoid this this function checks specifically 347 for operator tokens. 348 */ ExtractOperatorToken(string_type & a_sTok,int a_iPos) const349 int ParserTokenReader::ExtractOperatorToken(string_type &a_sTok, 350 int a_iPos) const 351 { 352 // Changed as per Issue 6: https://code.google.com/p/muparser/issues/detail?id=6 353 int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidOprtChars(), a_iPos); 354 if (iEnd==(int)string_type::npos) 355 iEnd = (int)m_strFormula.length(); 356 357 // Assign token string if there was something found 358 if (a_iPos!=iEnd) 359 { 360 a_sTok = string_type( m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd); 361 return iEnd; 362 } 363 else 364 { 365 // There is still the chance of having to deal with an operator consisting exclusively 366 // of alphabetic characters. 367 return ExtractToken(MUP_CHARS, a_sTok, a_iPos); 368 } 369 } 370 371 //--------------------------------------------------------------------------- 372 /** \brief Check if a built in operator or other token can be found 373 \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. 374 \return true if an operator token has been found. 375 */ IsBuiltIn(token_type & a_Tok)376 bool ParserTokenReader::IsBuiltIn(token_type &a_Tok) 377 { 378 const char_type **const pOprtDef = m_pParser->GetOprtDef(), 379 *const szFormula = m_strFormula.c_str(); 380 381 // Compare token with function and operator strings 382 // check string for operator/function 383 for (int i=0; pOprtDef[i]; i++) 384 { 385 std::size_t len( std::char_traits<char_type>::length(pOprtDef[i]) ); 386 if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) ) 387 { 388 switch(i) 389 { 390 //case cmAND: 391 //case cmOR: 392 //case cmXOR: 393 case cmLAND: 394 case cmLOR: 395 case cmLT: 396 case cmGT: 397 case cmLE: 398 case cmGE: 399 case cmNEQ: 400 case cmEQ: 401 case cmADD: 402 case cmSUB: 403 case cmMUL: 404 case cmDIV: 405 case cmPOW: 406 case cmASSIGN: 407 //if (len!=sTok.length()) 408 // continue; 409 410 // The assignment operator need special treatment 411 if (i==cmASSIGN && m_iSynFlags & noASSIGN) 412 Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); 413 414 if (!m_pParser->HasBuiltInOprt()) continue; 415 if (m_iSynFlags & noOPT) 416 { 417 // Maybe its an infix operator not an operator 418 // Both operator types can share characters in 419 // their identifiers 420 if ( IsInfixOpTok(a_Tok) ) 421 return true; 422 423 Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); 424 } 425 426 m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE | noEND; 427 break; 428 429 case cmBO: 430 if (m_iSynFlags & noBO) 431 Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); 432 433 if (m_lastTok.GetCode()==cmFUNC) 434 m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; 435 else 436 m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN| noIF | noELSE; 437 438 ++m_iBrackets; 439 break; 440 441 case cmBC: 442 if (m_iSynFlags & noBC) 443 Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); 444 445 m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; 446 447 if (--m_iBrackets<0) 448 Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); 449 break; 450 451 case cmELSE: 452 if (m_iSynFlags & noELSE) 453 Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); 454 455 m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; 456 break; 457 458 case cmIF: 459 if (m_iSynFlags & noIF) 460 Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); 461 462 m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; 463 break; 464 465 default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... 466 Error(ecINTERNAL_ERROR); 467 } // switch operator id 468 469 m_iPos += (int)len; 470 a_Tok.Set( (ECmdCode)i, pOprtDef[i] ); 471 return true; 472 } // if operator string found 473 } // end of for all operator strings 474 475 return false; 476 } 477 478 //--------------------------------------------------------------------------- IsArgSep(token_type & a_Tok)479 bool ParserTokenReader::IsArgSep(token_type &a_Tok) 480 { 481 const char_type* szFormula = m_strFormula.c_str(); 482 483 if (szFormula[m_iPos]==m_cArgSep) 484 { 485 // copy the separator into null terminated string 486 char_type szSep[2]; 487 szSep[0] = m_cArgSep; 488 szSep[1] = 0; 489 490 if (m_iSynFlags & noARG_SEP) 491 Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep); 492 493 m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN; 494 m_iPos++; 495 a_Tok.Set(cmARG_SEP, szSep); 496 return true; 497 } 498 499 return false; 500 } 501 502 //--------------------------------------------------------------------------- 503 /** \brief Check for End of Formula. 504 505 \return true if an end of formula is found false otherwise. 506 \param a_Tok [out] If an eof is found the corresponding token will be stored there. 507 \throw nothrow 508 \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok 509 */ IsEOF(token_type & a_Tok)510 bool ParserTokenReader::IsEOF(token_type &a_Tok) 511 { 512 const char_type* szFormula = m_strFormula.c_str(); 513 514 // check for EOF 515 if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/) 516 { 517 if ( m_iSynFlags & noEND ) 518 Error(ecUNEXPECTED_EOF, m_iPos); 519 520 if (m_iBrackets>0) 521 Error(ecMISSING_PARENS, m_iPos, _T(")")); 522 523 m_iSynFlags = 0; 524 a_Tok.Set(cmEND); 525 return true; 526 } 527 528 return false; 529 } 530 531 //--------------------------------------------------------------------------- 532 /** \brief Check if a string position contains a unary infix operator. 533 \return true if a function token has been found false otherwise. 534 */ IsInfixOpTok(token_type & a_Tok)535 bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok) 536 { 537 string_type sTok; 538 int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos); 539 if (iEnd==m_iPos) 540 return false; 541 542 // iterate over all postfix operator strings 543 funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin(); 544 for ( ; it!=m_pInfixOprtDef->rend(); ++it) 545 { 546 if (sTok.find(it->first)!=0) 547 continue; 548 549 a_Tok.Set(it->second, it->first); 550 m_iPos += (int)it->first.length(); 551 552 if (m_iSynFlags & noINFIXOP) 553 Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); 554 555 m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; 556 return true; 557 } 558 559 return false; 560 561 /* 562 a_Tok.Set(item->second, sTok); 563 m_iPos = (int)iEnd; 564 565 if (m_iSynFlags & noINFIXOP) 566 Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); 567 568 m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; 569 return true; 570 */ 571 } 572 573 //--------------------------------------------------------------------------- 574 /** \brief Check whether the token at a given position is a function token. 575 \param a_Tok [out] If a value token is found it will be placed here. 576 \throw ParserException if Syntaxflags do not allow a function at a_iPos 577 \return true if a function token has been found false otherwise. 578 \pre [assert] m_pParser!=0 579 */ IsFunTok(token_type & a_Tok)580 bool ParserTokenReader::IsFunTok(token_type &a_Tok) 581 { 582 string_type strTok; 583 int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); 584 if (iEnd==m_iPos) 585 return false; 586 587 funmap_type::const_iterator item = m_pFunDef->find(strTok); 588 if (item==m_pFunDef->end()) 589 return false; 590 591 // Check if the next sign is an opening bracket 592 const char_type *szFormula = m_strFormula.c_str(); 593 if (szFormula[iEnd]!='(') 594 return false; 595 596 a_Tok.Set(item->second, strTok); 597 598 m_iPos = (int)iEnd; 599 if (m_iSynFlags & noFUN) 600 Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString()); 601 602 m_iSynFlags = noANY ^ noBO; 603 return true; 604 } 605 606 //--------------------------------------------------------------------------- 607 /** \brief Check if a string position contains a binary operator. 608 \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. 609 \return true if an operator token has been found. 610 */ IsOprt(token_type & a_Tok)611 bool ParserTokenReader::IsOprt(token_type &a_Tok) 612 { 613 const char_type *const szExpr = m_strFormula.c_str(); 614 string_type strTok; 615 616 int iEnd = ExtractOperatorToken(strTok, m_iPos); 617 if (iEnd==m_iPos) 618 return false; 619 620 // Check if the operator is a built in operator, if so ignore it here 621 const char_type **const pOprtDef = m_pParser->GetOprtDef(); 622 for (int i=0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i) 623 { 624 if (string_type(pOprtDef[i])==strTok) 625 return false; 626 } 627 628 // Note: 629 // All tokens in oprt_bin_maptype are have been sorted by their length 630 // Long operators must come first! Otherwise short names (like: "add") that 631 // are part of long token names (like: "add123") will be found instead 632 // of the long ones. 633 // Length sorting is done with ascending length so we use a reverse iterator here. 634 funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin(); 635 for ( ; it!=m_pOprtDef->rend(); ++it) 636 { 637 const string_type &sID = it->first; 638 if ( sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()) ) 639 { 640 a_Tok.Set(it->second, strTok); 641 642 // operator was found 643 if (m_iSynFlags & noOPT) 644 { 645 // An operator was found but is not expected to occur at 646 // this position of the formula, maybe it is an infix 647 // operator, not a binary operator. Both operator types 648 // can share characters in their identifiers. 649 if ( IsInfixOpTok(a_Tok) ) 650 return true; 651 else 652 { 653 // nope, no infix operator 654 return false; 655 //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); 656 } 657 658 } 659 660 m_iPos += (int)sID.length(); 661 m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noASSIGN; 662 return true; 663 } 664 } 665 666 return false; 667 } 668 669 //--------------------------------------------------------------------------- 670 /** \brief Check if a string position contains a unary post value operator. */ IsPostOpTok(token_type & a_Tok)671 bool ParserTokenReader::IsPostOpTok(token_type &a_Tok) 672 { 673 // <ibg 20110629> Do not check for postfix operators if they are not allowed at 674 // the current expression index. 675 // 676 // This will fix the bug reported here: 677 // 678 // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979 679 // 680 if (m_iSynFlags & noPOSTOP) 681 return false; 682 // </ibg> 683 684 // Tricky problem with equations like "3m+5": 685 // m is a postfix operator, + is a valid sign for postfix operators and 686 // for binary operators parser detects "m+" as operator string and 687 // finds no matching postfix operator. 688 // 689 // This is a special case so this routine slightly differs from the other 690 // token readers. 691 692 // Test if there could be a postfix operator 693 string_type sTok; 694 int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos); 695 if (iEnd==m_iPos) 696 return false; 697 698 // iterate over all postfix operator strings 699 funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin(); 700 for ( ; it!=m_pPostOprtDef->rend(); ++it) 701 { 702 if (sTok.find(it->first)!=0) 703 continue; 704 705 a_Tok.Set(it->second, sTok); 706 m_iPos += (int)it->first.length(); 707 708 m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; 709 return true; 710 } 711 712 return false; 713 } 714 715 //--------------------------------------------------------------------------- 716 /** \brief Check whether the token at a given position is a value token. 717 718 Value tokens are either values or constants. 719 720 \param a_Tok [out] If a value token is found it will be placed here. 721 \return true if a value token has been found. 722 */ IsValTok(token_type & a_Tok)723 bool ParserTokenReader::IsValTok(token_type &a_Tok) 724 { 725 assert(m_pConstDef); 726 assert(m_pParser); 727 728 string_type strTok; 729 value_type fVal(0); 730 int iEnd(0); 731 732 // 2.) Check for user defined constant 733 // Read everything that could be a constant name 734 iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); 735 if (iEnd!=m_iPos) 736 { 737 valmap_type::const_iterator item = m_pConstDef->find(strTok); 738 if (item!=m_pConstDef->end()) 739 { 740 m_iPos = iEnd; 741 a_Tok.SetVal(item->second, strTok); 742 743 if (m_iSynFlags & noVAL) 744 Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); 745 746 m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; 747 return true; 748 } 749 } 750 751 // 3.call the value recognition functions provided by the user 752 // Call user defined value recognition functions 753 std::list<identfun_type>::const_iterator item = m_vIdentFun.begin(); 754 for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item) 755 { 756 int iStart = m_iPos; 757 if ( (*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal)==1 ) 758 { 759 // 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2 760 strTok.assign(m_strFormula.c_str(), iStart, m_iPos-iStart); 761 762 if (m_iSynFlags & noVAL) 763 Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); 764 765 a_Tok.SetVal(fVal, strTok); 766 m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; 767 return true; 768 } 769 } 770 771 return false; 772 } 773 774 //--------------------------------------------------------------------------- 775 /** \brief Check wheter a token at a given position is a variable token. 776 \param a_Tok [out] If a variable token has been found it will be placed here. 777 \return true if a variable token has been found. 778 */ IsVarTok(token_type & a_Tok)779 bool ParserTokenReader::IsVarTok(token_type &a_Tok) 780 { 781 if (m_pVarDef->empty()) 782 return false; 783 784 string_type strTok; 785 int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); 786 if (iEnd==m_iPos) 787 return false; 788 789 varmap_type::const_iterator item = m_pVarDef->find(strTok); 790 if (item==m_pVarDef->end()) 791 return false; 792 793 if (m_iSynFlags & noVAR) 794 Error(ecUNEXPECTED_VAR, m_iPos, strTok); 795 796 m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd); 797 798 m_iPos = iEnd; 799 a_Tok.SetVar(item->second, strTok); 800 m_UsedVar[item->first] = item->second; // Add variable to used-var-list 801 802 m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR; 803 804 // Zur Info hier die SynFlags von IsVal(): 805 // m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; 806 return true; 807 } 808 809 //--------------------------------------------------------------------------- IsStrVarTok(token_type & a_Tok)810 bool ParserTokenReader::IsStrVarTok(token_type &a_Tok) 811 { 812 if (!m_pStrVarDef || m_pStrVarDef->empty()) 813 return false; 814 815 string_type strTok; 816 int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); 817 if (iEnd==m_iPos) 818 return false; 819 820 strmap_type::const_iterator item = m_pStrVarDef->find(strTok); 821 if (item==m_pStrVarDef->end()) 822 return false; 823 824 if (m_iSynFlags & noSTR) 825 Error(ecUNEXPECTED_VAR, m_iPos, strTok); 826 827 m_iPos = iEnd; 828 if (!m_pParser->m_vStringVarBuf.size()) 829 Error(ecINTERNAL_ERROR); 830 831 a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() ); 832 833 m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noARG_SEP); 834 return true; 835 } 836 837 838 //--------------------------------------------------------------------------- 839 /** \brief Check wheter a token at a given position is an undefined variable. 840 841 \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here. 842 \return true if a variable token has been found. 843 \throw nothrow 844 */ IsUndefVarTok(token_type & a_Tok)845 bool ParserTokenReader::IsUndefVarTok(token_type &a_Tok) 846 { 847 string_type strTok; 848 int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos) ); 849 if ( iEnd==m_iPos ) 850 return false; 851 852 if (m_iSynFlags & noVAR) 853 { 854 // <ibg/> 20061021 added token string strTok instead of a_Tok.GetAsString() as the 855 // token identifier. 856 // related bug report: 857 // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979 858 Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok); 859 } 860 861 // If a factory is available implicitely create new variables 862 if (m_pFactory) 863 { 864 value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData); 865 a_Tok.SetVar(fVar, strTok ); 866 867 // Do not use m_pParser->DefineVar( strTok, fVar ); 868 // in order to define the new variable, it will clear the 869 // m_UsedVar array which will kill previousely defined variables 870 // from the list 871 // This is safe because the new variable can never override an existing one 872 // because they are checked first! 873 (*m_pVarDef)[strTok] = fVar; 874 m_UsedVar[strTok] = fVar; // Add variable to used-var-list 875 } 876 else 877 { 878 a_Tok.SetVar((value_type*)&m_fZero, strTok); 879 m_UsedVar[strTok] = 0; // Add variable to used-var-list 880 } 881 882 m_iPos = iEnd; 883 884 // Call the variable factory in order to let it define a new parser variable 885 m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; 886 return true; 887 } 888 889 890 //--------------------------------------------------------------------------- 891 /** \brief Check wheter a token at a given position is a string. 892 \param a_Tok [out] If a variable token has been found it will be placed here. 893 \return true if a string token has been found. 894 \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok 895 \throw nothrow 896 */ IsString(token_type & a_Tok)897 bool ParserTokenReader::IsString(token_type &a_Tok) 898 { 899 if (m_strFormula[m_iPos]!='"') 900 return false; 901 902 string_type strBuf(&m_strFormula[m_iPos+1]); 903 std::size_t iEnd(0), iSkip(0); 904 905 // parser over escaped '\"' end replace them with '"' 906 for(iEnd=(int)strBuf.find( _T("\"") ); iEnd!=0 && iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T("\""), iEnd)) 907 { 908 if (strBuf[iEnd-1]!='\\') break; 909 strBuf.replace(iEnd-1, 2, _T("\"") ); 910 iSkip++; 911 } 912 913 if (iEnd==string_type::npos) 914 Error(ecUNTERMINATED_STRING, m_iPos, _T("\"") ); 915 916 string_type strTok(strBuf.begin(), strBuf.begin()+iEnd); 917 918 if (m_iSynFlags & noSTR) 919 Error(ecUNEXPECTED_STR, m_iPos, strTok); 920 921 m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer 922 a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size()); 923 924 m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 wg Anführungszeichen; +iSkip für entfernte escape zeichen 925 m_iSynFlags = noANY ^ ( noARG_SEP | noBC | noOPT | noEND ); 926 927 return true; 928 } 929 930 //--------------------------------------------------------------------------- 931 /** \brief Create an error containing the parse error position. 932 933 This function will create an Parser Exception object containing the error text and its position. 934 935 \param a_iErrc [in] The error code of type #EErrorCodes. 936 \param a_iPos [in] The position where the error was detected. 937 \param a_strTok [in] The token string representation associated with the error. 938 \throw ParserException always throws thats the only purpose of this function. 939 */ Error(EErrorCodes a_iErrc,int a_iPos,const string_type & a_sTok) const940 void ParserTokenReader::Error( EErrorCodes a_iErrc, 941 int a_iPos, 942 const string_type &a_sTok) const 943 { 944 m_pParser->Error(a_iErrc, a_iPos, a_sTok); 945 } 946 947 //--------------------------------------------------------------------------- SetArgSep(char_type cArgSep)948 void ParserTokenReader::SetArgSep(char_type cArgSep) 949 { 950 m_cArgSep = cArgSep; 951 } 952 953 //--------------------------------------------------------------------------- GetArgSep() const954 char_type ParserTokenReader::GetArgSep() const 955 { 956 return m_cArgSep; 957 } 958 } // namespace mu 959 960