muParserTokenReader.cpp 31.6 KB
Newer Older
1
/*
2 3
                 __________
    _____   __ __\______   \_____  _______  ______  ____ _______
4 5
   /     \ |  |  \|     ___/\__  \ \_  __ \/  ___/_/ __ \\_  __ \
  |  Y Y  \|  |  /|    |     / __ \_|  | \/\___ \ \  ___/ |  | \/
6 7
  |__|_|  /|____/ |____|    (____  /|__|  /____  > \___  >|__|
        \/                       \/            \/      \/
8 9
  Copyright (C) 2010 Ingo Berg

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 13
  without restriction, including without limitation the rights to use, copy, modify,
  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
14 15
  permit persons to whom the Software is furnished to do so, subject to the following conditions:

16
  The above copyright notice and this permission notice shall be included in all copies or
17 18 19
  substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
20 21 22 23
  NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
*/
#include <cassert>
#include <cstdio>
#include <cstring>
#include <map>
#include <stack>
#include <string>

#include "muParserTokenReader.h"
#include "muParserBase.h"

/** \file
    \brief This file contains the parser token reader implementation.
*/


namespace mu
{

  // Forward declaration
  class ParserBase;

  //---------------------------------------------------------------------------
  /** \brief Copy constructor.

      \sa Assign
      \throw nothrow
  */
52 53
  ParserTokenReader::ParserTokenReader(const ParserTokenReader &a_Reader)
  {
54 55
    Assign(a_Reader);
  }
56

57 58 59 60 61 62 63 64
  //---------------------------------------------------------------------------
  /** \brief Assignement operator.

      Self assignement will be suppressed otherwise #Assign is called.

      \param a_Reader Object to copy to this token reader.
      \throw nothrow
  */
65
  ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader &a_Reader)
66 67 68 69 70 71 72 73
  {
    if (&a_Reader!=this)
      Assign(a_Reader);

    return *this;
  }

  //---------------------------------------------------------------------------
74 75
  /** \brief Assign state of a token reader to this token reader.

76 77 78 79 80 81 82 83 84
      \param a_Reader Object from which the state should be copied.
      \throw nothrow
  */
  void ParserTokenReader::Assign(const ParserTokenReader &a_Reader)
  {
    m_pParser = a_Reader.m_pParser;
    m_strFormula = a_Reader.m_strFormula;
    m_iPos = a_Reader.m_iPos;
    m_iSynFlags = a_Reader.m_iSynFlags;
85

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
    m_UsedVar         = a_Reader.m_UsedVar;
    m_pFunDef         = a_Reader.m_pFunDef;
    m_pConstDef       = a_Reader.m_pConstDef;
    m_pVarDef         = a_Reader.m_pVarDef;
    m_pStrVarDef      = a_Reader.m_pStrVarDef;
    m_pPostOprtDef    = a_Reader.m_pPostOprtDef;
    m_pInfixOprtDef   = a_Reader.m_pInfixOprtDef;
    m_pOprtDef        = a_Reader.m_pOprtDef;
    m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar;
    m_vIdentFun       = a_Reader.m_vIdentFun;
    m_pFactory        = a_Reader.m_pFactory;
    m_pFactoryData    = a_Reader.m_pFactoryData;
    m_iBrackets       = a_Reader.m_iBrackets;
    m_cArgSep         = a_Reader.m_cArgSep;
  }

  //---------------------------------------------------------------------------
103 104 105
  /** \brief Constructor.

      Create a Token reader and bind it to a parser object.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135

      \pre [assert] a_pParser may not be NULL
      \post #m_pParser==a_pParser
      \param a_pParent Parent parser object of the token reader.
  */
  ParserTokenReader::ParserTokenReader(ParserBase *a_pParent)
    :m_pParser(a_pParent)
    ,m_strFormula()
    ,m_iPos(0)
    ,m_iSynFlags(0)
    ,m_bIgnoreUndefVar(false)
    ,m_pFunDef(NULL)
    ,m_pPostOprtDef(NULL)
    ,m_pInfixOprtDef(NULL)
    ,m_pOprtDef(NULL)
    ,m_pConstDef(NULL)
    ,m_pStrVarDef(NULL)
    ,m_pVarDef(NULL)
    ,m_pFactory(NULL)
    ,m_pFactoryData(NULL)
    ,m_vIdentFun()
    ,m_UsedVar()
    ,m_fZero(0)
    ,m_iBrackets(0)
    ,m_lastTok()
    ,m_cArgSep(',')
  {
    assert(m_pParser);
    SetParent(m_pParser);
  }
136

137
  //---------------------------------------------------------------------------
138 139
  /** \brief Create instance of a ParserTokenReader identical with this
              and return its pointer.
140 141 142 143 144 145 146 147

      This is a factory method the calling function must take care of the object destruction.

      \return A new ParserTokenReader object.
      \throw nothrow
  */
  ParserTokenReader* ParserTokenReader::Clone(ParserBase *a_pParent) const
  {
148
#if MUPARSER_HAS_CXX11
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    std::unique_ptr<ParserTokenReader> ptr(new ParserTokenReader(*this));
#else
    std::auto_ptr<ParserTokenReader> ptr(new ParserTokenReader(*this));
#endif
    ptr->SetParent(a_pParent);
    return ptr.release();
  }

  //---------------------------------------------------------------------------
  ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type &tok)
  {
    m_lastTok = tok;
    return m_lastTok;
  }

  //---------------------------------------------------------------------------
  void ParserTokenReader::AddValIdent(identfun_type a_pCallback)
  {
    m_vIdentFun.push_back(a_pCallback);
  }

  //---------------------------------------------------------------------------
  void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void *pUserData)
  {
    m_pFactory = a_pFactory;
    m_pFactoryData = pUserData;
  }

  //---------------------------------------------------------------------------
178
  /** \brief Return the current position of the token reader in the formula string.
179 180 181 182 183 184 185 186 187 188

      \return #m_iPos
      \throw nothrow
  */
  int ParserTokenReader::GetPos() const
  {
    return m_iPos;
  }

  //---------------------------------------------------------------------------
189
  /** \brief Return a reference to the formula.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206

      \return #m_strFormula
      \throw nothrow
  */
  const string_type& ParserTokenReader::GetExpr() const
  {
    return m_strFormula;
  }

  //---------------------------------------------------------------------------
  /** \brief Return a map containing the used variables only. */
  const varmap_type& ParserTokenReader::GetUsedVar() const
  {
    return m_UsedVar;
  }

  //---------------------------------------------------------------------------
207 208
  /** \brief Initialize the token Reader.

209 210 211 212 213 214 215 216 217 218
      Sets the formula position index to zero and set Syntax flags to default for initial formula parsing.
      \pre [assert] triggered if a_szFormula==0
  */
  void ParserTokenReader::SetFormula(const string_type &a_strFormula)
  {
    m_strFormula = a_strFormula;
    ReInit();
  }

  //---------------------------------------------------------------------------
219 220 221
  /** \brief Set Flag that contronls behaviour in case of undefined variables beeing found.

    If true, the parser does not throw an exception if an undefined variable is found.
222
    otherwise it does. This variable is used internally only!
223 224
    It supresses a "undefined variable" exception in GetUsedVar().
    Those function should return a complete list of variables including
225 226 227 228 229 230 231 232
    those the are not defined by the time of it's call.
  */
  void ParserTokenReader::IgnoreUndefVar(bool bIgnore)
  {
    m_bIgnoreUndefVar = bIgnore;
  }

  //---------------------------------------------------------------------------
233
  /** \brief Reset the token reader to the start of the formula.
234

235
      The syntax flags will be reset to a value appropriate for the
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
      start of a formula.
      \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR
      \throw nothrow
      \sa ESynCodes
  */
  void ParserTokenReader::ReInit()
  {
    m_iPos = 0;
    m_iSynFlags = noOPT | noBC | noPOSTOP | noASSIGN;
    m_iBrackets = 0;
    m_UsedVar.clear();
    m_lastTok = token_type();
  }

  //---------------------------------------------------------------------------
251
  /** \brief Read the next token from the string. */
252 253 254 255 256 257 258 259 260
  ParserTokenReader::token_type ParserTokenReader::ReadNextToken()
  {
    assert(m_pParser);

    std::stack<int> FunArgs;
    const char_type *szFormula = m_strFormula.c_str();
    token_type tok;

    // Ignore all non printable characters when reading the expression
261
    while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20)
262 263 264 265 266 267 268 269 270 271 272 273 274 275
      ++m_iPos;

    if ( IsEOF(tok) )        return SaveBeforeReturn(tok); // Check for end of formula
    if ( IsOprt(tok) )       return SaveBeforeReturn(tok); // Check for user defined binary operator
    if ( IsFunTok(tok) )     return SaveBeforeReturn(tok); // Check for function token
    if ( IsBuiltIn(tok) )    return SaveBeforeReturn(tok); // Check built in operators / tokens
    if ( IsArgSep(tok) )     return SaveBeforeReturn(tok); // Check for function argument separators
    if ( IsValTok(tok) )     return SaveBeforeReturn(tok); // Check for values / constant tokens
    if ( IsVarTok(tok) )     return SaveBeforeReturn(tok); // Check for variable tokens
    if ( IsStrVarTok(tok) )  return SaveBeforeReturn(tok); // Check for string variables
    if ( IsString(tok) )     return SaveBeforeReturn(tok); // Check for String tokens
    if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators
    if ( IsPostOpTok(tok) )  return SaveBeforeReturn(tok); // Check for unary operators

276
    // Check String for undefined variable token. Done only if a
277
    // flag is set indicating to ignore undefined variables.
278 279
    // This is a way to conditionally avoid an error if
    // undefined variables occur.
280
    // The GetUsedVar function must supress the error for
281
    // undefined variables in order to collect all variable
282
    // names including the undefined ones.
283
    if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) )
284 285 286
      return SaveBeforeReturn(tok);

    // Check for unknown token
287
    //
288
    // !!! From this point on there is no exit without an exception possible...
289
    //
290 291 292 293 294 295 296 297 298 299 300 301
    string_type strTok;
    int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
    if (iEnd!=m_iPos)
      Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok);

    Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos));
    return token_type(); // never reached
  }

  //---------------------------------------------------------------------------
  void ParserTokenReader::SetParent(ParserBase *a_pParent)
  {
302
    m_pParser       = a_pParent;
303 304 305 306 307 308 309 310 311 312 313 314
    m_pFunDef       = &a_pParent->m_FunDef;
    m_pOprtDef      = &a_pParent->m_OprtDef;
    m_pInfixOprtDef = &a_pParent->m_InfixOprtDef;
    m_pPostOprtDef  = &a_pParent->m_PostOprtDef;
    m_pVarDef       = &a_pParent->m_VarDef;
    m_pStrVarDef    = &a_pParent->m_StrVarDef;
    m_pConstDef     = &a_pParent->m_ConstDef;
  }

  //---------------------------------------------------------------------------
  /** \brief Extract all characters that belong to a certain charset.

315
    \param a_szCharSet [in] Const char array of the characters allowed in the token.
316 317 318 319 320
    \param a_strTok [out]  The string that consists entirely of characters listed in a_szCharSet.
    \param a_iPos [in] Position in the string from where to start reading.
    \return The Position of the first character not listed in a_szCharSet.
    \throw nothrow
  */
321 322
  int ParserTokenReader::ExtractToken(const char_type *a_szCharSet,
                                      string_type &a_sTok,
323 324 325 326 327 328
                                      int a_iPos) const
  {
    int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos);

    if (iEnd==(int)string_type::npos)
        iEnd = (int)m_strFormula.length();
329

330 331 332 333 334 335 336 337 338
    // Assign token string if there was something found
    if (a_iPos!=iEnd)
      a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd);

    return iEnd;
  }

  //---------------------------------------------------------------------------
  /** \brief Check Expression for the presence of a binary operator token.
339

340 341 342 343 344
    Userdefined binary operator "++" gives inconsistent parsing result for
    the equations "a++b" and "a ++ b" if alphabetic characters are allowed
    in operator tokens. To avoid this this function checks specifically
    for operator tokens.
  */
345
  int ParserTokenReader::ExtractOperatorToken(string_type &a_sTok,
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
                                              int a_iPos) const
  {
    int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidInfixOprtChars(), a_iPos);
    if (iEnd==(int)string_type::npos)
      iEnd = (int)m_strFormula.length();

    // Assign token string if there was something found
    if (a_iPos!=iEnd)
    {
      a_sTok = string_type( m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd);
      return iEnd;
    }
    else
    {
      // There is still the chance of having to deal with an operator consisting exclusively
      // of alphabetic characters.
      return ExtractToken(MUP_CHARS, a_sTok, a_iPos);
    }
  }

  //---------------------------------------------------------------------------
  /** \brief Check if a built in operator or other token can be found
      \param a_Tok  [out] Operator token if one is found. This can either be a binary operator or an infix operator token.
      \return true if an operator token has been found.
  */
  bool ParserTokenReader::IsBuiltIn(token_type &a_Tok)
  {
    const char_type **const pOprtDef = m_pParser->GetOprtDef(),
                     *const szFormula = m_strFormula.c_str();

    // Compare token with function and operator strings
    // check string for operator/function
    for (int i=0; pOprtDef[i]; i++)
    {
      std::size_t len( std::char_traits<char_type>::length(pOprtDef[i]) );
      if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) )
      {
        switch(i)
        {
        case cmAND:
        case cmOR:
        case cmXOR:
        case cmLT:
        case cmGT:
        case cmLE:
        case cmGE:
392
        case cmNEQ:
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
        case cmEQ:
        case cmADD:
        case cmSUB:
        case cmMUL:
        case cmDIV:
        case cmPOW:
        case cmASSIGN:
              //if (len!=sTok.length())
              //  continue;

              // The assignement operator need special treatment
              if (i==cmASSIGN && m_iSynFlags & noASSIGN)
                Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);

              if (!m_pParser->HasBuiltInOprt()) continue;
408
              if (m_iSynFlags & noOPT)
409 410
              {
                // Maybe its an infix operator not an operator
411
                // Both operator types can share characters in
412
                // their identifiers
413
                if ( IsInfixOpTok(a_Tok) )
414 415 416 417 418 419 420 421 422 423 424 425
                  return true;

                Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
              }

              m_iSynFlags  = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN;
              m_iSynFlags |= ( (i != cmEND) && ( i != cmBC) ) ? noEND : 0;
              break;

		    case cmBO:
              if (m_iSynFlags & noBO)
	              Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
426

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
              if (m_lastTok.GetCode()==cmFUNC)
                m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN;
              else
                m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN;

              ++m_iBrackets;
              break;

		    case cmBC:
              if (m_iSynFlags & noBC)
                Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);

              m_iSynFlags  = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN;

              if (--m_iBrackets<0)
                Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
              break;
444

445 446 447 448 449 450 451 452 453
		    default:      // The operator is listed in c_DefaultOprt, but not here. This is a bad thing...
              Error(ecINTERNAL_ERROR);
        } // switch operator id

        m_iPos += (int)len;
        a_Tok.Set( (ECmdCode)i, pOprtDef[i] );
        return true;
	    } // if operator string found
    } // end of for all operator strings
454

455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
    return false;
  }

  //---------------------------------------------------------------------------
  bool ParserTokenReader::IsArgSep(token_type &a_Tok)
  {
    const char_type* szFormula = m_strFormula.c_str();

    if (szFormula[m_iPos]==m_cArgSep)
    {
      // copy the separator into null terminated string
      char_type szSep[2];
      szSep[0] = m_cArgSep;
      szSep[1] = 0;

      if (m_iSynFlags & noARG_SEP)
        Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep);

      m_iSynFlags  = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN;
      m_iPos++;
      a_Tok.Set(cmARG_SEP, szSep);
      return true;
    }

    return false;
  }

  //---------------------------------------------------------------------------
  /** \brief Check for End of Formula.

      \return true if an end of formula is found false otherwise.
      \param a_Tok [out] If an eof is found the corresponding token will be stored there.
      \throw nothrow
      \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok
  */
  bool ParserTokenReader::IsEOF(token_type &a_Tok)
  {
    const char_type* szFormula = m_strFormula.c_str();

    // check for EOF
    if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/)
    {
      if ( m_iSynFlags & noEND )
        Error(ecUNEXPECTED_EOF, m_iPos);

      if (m_iBrackets>0)
        Error(ecMISSING_PARENS, m_iPos, _T(")"));

      m_iSynFlags = 0;
      a_Tok.Set(cmEND);
      return true;
    }

    return false;
  }

  //---------------------------------------------------------------------------
512
  /** \brief Check if a string position contains a unary infix operator.
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
      \return true if a function token has been found false otherwise.
  */
  bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok)
  {
    string_type sTok;
    int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos);
    if (iEnd==m_iPos)
      return false;

    funmap_type::const_iterator item = m_pInfixOprtDef->find(sTok);
    if (item==m_pInfixOprtDef->end())
      return false;

    a_Tok.Set(item->second, sTok);
    m_iPos = (int)iEnd;

529
    if (m_iSynFlags & noINFIXOP)
530 531
      Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());

532
    m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN;
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
    return true;
  }

  //---------------------------------------------------------------------------
  /** \brief Check whether the token at a given position is a function token.
      \param a_Tok [out] If a value token is found it will be placed here.
      \throw ParserException if Syntaxflags do not allow a function at a_iPos
      \return true if a function token has been found false otherwise.
      \pre [assert] m_pParser!=0
  */
  bool ParserTokenReader::IsFunTok(token_type &a_Tok)
  {
    string_type strTok;
    int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
    if (iEnd==m_iPos)
      return false;

    funmap_type::const_iterator item = m_pFunDef->find(strTok);
    if (item==m_pFunDef->end())
      return false;

    // Check if the next sign is an opening bracket
    const char_type *szFormula = m_strFormula.c_str();
    if (szFormula[iEnd]!='(')
      return false;

    a_Tok.Set(item->second, strTok);

    m_iPos = (int)iEnd;
    if (m_iSynFlags & noFUN)
      Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString());

    m_iSynFlags = noANY ^ noBO;
    return true;
  }

  //---------------------------------------------------------------------------
  /** \brief Check if a string position contains a binary operator.
      \param a_Tok  [out] Operator token if one is found. This can either be a binary operator or an infix operator token.
      \return true if an operator token has been found.
  */
  bool ParserTokenReader::IsOprt(token_type &a_Tok)
  {
    const char_type *const szExpr = m_strFormula.c_str();
    string_type strTok;

    int iEnd = ExtractOperatorToken(strTok, m_iPos);
    if (iEnd==m_iPos)
      return false;

    // Note:
    // All tokens in oprt_bin_maptype are have been sorted by their length
    // Long operators must come first! Otherwise short names (like: "add") that
586
    // are part of long token names (like: "add123") will be found instead
587 588 589 590 591 592 593 594 595 596 597
    // of the long ones.
    // Length sorting is done with ascending length so we use a reverse iterator here.
    funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin();
    for ( ; it!=m_pOprtDef->rend(); ++it)
    {
      const string_type &sID = it->first;
      if ( sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()) )
      {
        a_Tok.Set(it->second, strTok);

        // operator was found
598
        if (m_iSynFlags & noOPT)
599 600
        {
          // An operator was found but is not expected to occur at
601
          // this position of the formula, maybe it is an infix
602 603
          // operator, not a binary operator. Both operator types
          // can share characters in their identifiers.
604
          if ( IsInfixOpTok(a_Tok) )
605 606
            return true;
          // nope, no infix operator
607
          Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
        }

        m_iPos += (int)sID.length();
        m_iSynFlags  = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noBC | noASSIGN;
        return true;
      }
    }

    return false;
  }

  //---------------------------------------------------------------------------
  /** \brief Check if a string position contains a unary post value operator. */
  bool ParserTokenReader::IsPostOpTok(token_type &a_Tok)
  {
    // Tricky problem with equations like "3m+5":
624 625
    //     m is a postfix operator, + is a valid sign for postfix operators and
    //     for binary operators parser detects "m+" as operator string and
626
    //     finds no matching postfix operator.
627
    //
628 629
    // This is a special case so this routine slightly differs from the other
    // token readers.
630

631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
    // Test if there could be a postfix operator
    string_type sTok;
    int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos);
    if (iEnd==m_iPos)
      return false;

    // iteraterate over all postfix operator strings
    funmap_type::const_iterator item = m_pPostOprtDef->begin();
    for (item=m_pPostOprtDef->begin(); item!=m_pPostOprtDef->end(); ++item)
    {
      if (sTok.find(item->first)!=0)
        continue;

      a_Tok.Set(item->second, sTok);
  	  m_iPos += (int)item->first.length();

      if (m_iSynFlags & noPOSTOP)
        Error(ecUNEXPECTED_OPERATOR, m_iPos-(int)item->first.length(), item->first);

      m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN;
      return true;
    }

    return false;
  }

  //---------------------------------------------------------------------------
  /** \brief Check whether the token at a given position is a value token.

    Value tokens are either values or constants.

    \param a_Tok [out] If a value token is found it will be placed here.
    \return true if a value token has been found.
  */
  bool ParserTokenReader::IsValTok(token_type &a_Tok)
  {
    assert(m_pConstDef);
    assert(m_pParser);

    #if defined(_MSC_VER)
      #pragma warning( disable : 4244 )
    #endif

    string_type strTok;
    value_type fVal(0);
    int iEnd(0);
677

678 679 680 681 682 683 684 685 686 687 688 689 690 691
    // 2.) Check for user defined constant
    // Read everything that could be a constant name
    iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
    if (iEnd!=m_iPos)
    {
      valmap_type::const_iterator item = m_pConstDef->find(strTok);
      if (item!=m_pConstDef->end())
      {
        m_iPos = iEnd;
        a_Tok.SetVal(item->second, strTok);

        if (m_iSynFlags & noVAL)
          Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);

692
        m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
        return true;
      }
    }

    // 3.call the value recognition functions provided by the user
    // Call user defined value recognition functions
    std::vector<identfun_type>::const_iterator item = m_vIdentFun.begin();
    for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item)
    {
      int iStart = m_iPos;
      if ( (*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal)==1 )
      {
        strTok.assign(m_strFormula.c_str(), iStart, m_iPos);
        if (m_iSynFlags & noVAL)
          Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);

        a_Tok.SetVal(fVal, strTok);
        m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
        return true;
      }
    }

    return false;

    #if defined(_MSC_VER)
      #pragma warning( default : 4244 )
    #endif
  }

  //---------------------------------------------------------------------------
723
  /** \brief Check wheter a token at a given position is a variable token.
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
      \param a_Tok [out] If a variable token has been found it will be placed here.
	    \return true if a variable token has been found.
  */
  bool ParserTokenReader::IsVarTok(token_type &a_Tok)
  {
    if (!m_pVarDef->size())
      return false;

    string_type strTok;
    int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
    if (iEnd==m_iPos)
      return false;

    varmap_type::const_iterator item =  m_pVarDef->find(strTok);
    if (item==m_pVarDef->end())
      return false;

    if (m_iSynFlags & noVAR)
      Error(ecUNEXPECTED_VAR, m_iPos, strTok);

    m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd);

    m_iPos = iEnd;
    a_Tok.SetVar(item->second, strTok);
    m_UsedVar[item->first] = item->second;  // Add variable to used-var-list

    m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR;

//  Zur Info hier die SynFlags von IsVal():
753
//    m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
    return true;
  }

  //---------------------------------------------------------------------------
  bool ParserTokenReader::IsStrVarTok(token_type &a_Tok)
  {
    if (!m_pStrVarDef || !m_pStrVarDef->size())
      return false;

    string_type strTok;
    int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
    if (iEnd==m_iPos)
      return false;

    strmap_type::const_iterator item =  m_pStrVarDef->find(strTok);
    if (item==m_pStrVarDef->end())
      return false;

    if (m_iSynFlags & noSTR)
      Error(ecUNEXPECTED_VAR, m_iPos, strTok);

    m_iPos = iEnd;
    if (!m_pParser->m_vStringVarBuf.size())
      Error(ecINTERNAL_ERROR);

    a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() );

    m_iSynFlags = m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noARG_SEP);
    return true;
  }


  //---------------------------------------------------------------------------
787
  /** \brief Check wheter a token at a given position is an undefined variable.
788 789 790 791 792 793 794 795 796 797 798 799 800 801

      \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here.
	    \return true if a variable token has been found.
      \throw nothrow
  */
  bool ParserTokenReader::IsUndefVarTok(token_type &a_Tok)
  {
    string_type strTok;
    int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos) );
    if ( iEnd==m_iPos )
      return false;

    if (m_iSynFlags & noVAR)
    {
802 803
      // <ibg/> 20061021 added token string strTok instead of a_Tok.GetAsString() as the
      //                 token identifier.
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
      // related bug report:
      // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979
      Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok);
    }

    // If a factory is available implicitely create new variables
    if (m_pFactory)
    {
      value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData);
      a_Tok.SetVar(fVar, strTok );

      // Do not use m_pParser->DefineVar( strTok, fVar );
      // in order to define the new variable, it will clear the
      // m_UsedVar array which will kill previousely defined variables
      // from the list
      // This is safe because the new variable can never override an existing one
      // because they are checked first!
      (*m_pVarDef)[strTok] = fVar;
      m_UsedVar[strTok] = fVar;  // Add variable to used-var-list
    }
    else
    {
      a_Tok.SetVar((value_type*)&m_fZero, strTok);
      m_UsedVar[strTok] = 0;  // Add variable to used-var-list
    }

    m_iPos = iEnd;

    // Call the variable factory in order to let it define a new parser variable
    m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR;
    return true;
  }


  //---------------------------------------------------------------------------
  /** \brief Check wheter a token at a given position is a string.
      \param a_Tok [out] If a variable token has been found it will be placed here.
  	  \return true if a string token has been found.
      \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok
      \throw nothrow
  */
  bool ParserTokenReader::IsString(token_type &a_Tok)
  {
847
    if (m_strFormula[m_iPos]!='"')
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
      return false;

    string_type strBuf(&m_strFormula[m_iPos+1]);
    std::size_t iEnd(0), iSkip(0);

    // parser over escaped '\"' end replace them with '"'
    for(iEnd=(int)strBuf.find( _T("\"") ); iEnd!=0 && iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T("\""), iEnd))
    {
      if (strBuf[iEnd-1]!='\\') break;
      strBuf.replace(iEnd-1, 2, _T("\"") );
      iSkip++;
    }

    if (iEnd==string_type::npos)
      Error(ecUNTERMINATED_STRING, m_iPos, _T("\"") );

    string_type strTok(strBuf.begin(), strBuf.begin()+iEnd);

    if (m_iSynFlags & noSTR)
      Error(ecUNEXPECTED_STR, m_iPos, strTok);

		m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer
    a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size());

    m_iPos += (int)strTok.length() + 2 + (int)iSkip;  // +2 wg Anführungszeichen; +iSkip für entfernte escape zeichen
    m_iSynFlags = m_iSynFlags = noANY ^ ( noARG_SEP | noBC | noOPT | noEND );

    return true;
  }

  //---------------------------------------------------------------------------
  /** \brief Create an error containing the parse error position.

    This function will create an Parser Exception object containing the error text and its position.

    \param a_iErrc [in] The error code of type #EErrorCodes.
    \param a_iPos [in] The position where the error was detected.
    \param a_strTok [in] The token string representation associated with the error.
    \throw ParserException always throws thats the only purpose of this function.
  */
888 889
  void  ParserTokenReader::Error( EErrorCodes a_iErrc,
                                  int a_iPos,
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
                                  const string_type &a_sTok) const
  {
    m_pParser->Error(a_iErrc, a_iPos, a_sTok);
  }

  //---------------------------------------------------------------------------
  void ParserTokenReader::SetArgSep(char_type cArgSep)
  {
    m_cArgSep = cArgSep;
  }

  //---------------------------------------------------------------------------
  char_type ParserTokenReader::GetArgSep() const
  {
    return m_cArgSep;
  }
} // namespace mu