⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 muparsertokenreader.cpp

📁 Mathematical expressions parser library
💻 CPP
📖 第 1 页 / 共 2 页
字号:
 /*
  Copyright (C) 2005 Ingo Berg

  Permission is hereby granted, free of charge, to any person obtaining a copy of this 
  software and associated documentation files (the "Software"), to deal in the Software
  without restriction, including without limitation the rights to use, copy, modify, 
  merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 
  permit persons to whom the Software is furnished to do so, subject to the following conditions:

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

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
  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. 
*/
#include <cassert>
#include <cstdio>
#include <cstring>
#include <map>
#include <stack>
#include <string>

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


namespace mu
{

  // Forward declaration
  class ParserBase;

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

      \sa Assign
      \throw nothrow
  */
  ParserTokenReader::ParserTokenReader(const ParserTokenReader &a_Reader) 
  { 
    Assign(a_Reader);
  }
    
  //---------------------------------------------------------------------------
  /** \brief Assignement operator.

      Self assignement will be suppressed otherwise #Assign is called.

      \param a_Reader Object to copy to this token reader.
      \throw nothrow
  */
  ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader &a_Reader) 
  {
    if (&a_Reader!=this)
      Assign(a_Reader);

    return *this;
  }

  //---------------------------------------------------------------------------
  /** \brief Assign state of a token reader to this token reader. 
      
      \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;
    
    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;
  }

  //---------------------------------------------------------------------------
  /** \brief Constructor. 
      
      Create a Token reader and bind it to a parser object. 

      \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(0)
    ,m_pPostOprtDef(0)
    ,m_pInfixOprtDef(0)
    ,m_pOprtDef(0)
    ,m_pConstDef(0)
    ,m_pStrVarDef(0)
    ,m_pVarDef(0)
    ,m_pFactory(0)
    ,m_vIdentFun()
    ,m_UsedVar()
    ,m_fZero(0)
  {
    assert(m_pParser);
    SetParent(m_pParser);
  }
    
  //---------------------------------------------------------------------------
  /** \brief Destructor (trivial).
  
      \throw nothrow
  */
  ParserTokenReader::~ParserTokenReader()
  {}

  //---------------------------------------------------------------------------
  /** \brief Create instance of a ParserTokenReader identical with this 
              and return its pointer. 

      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
  {
    std::auto_ptr<ParserTokenReader> ptr(new ParserTokenReader(*this));
    ptr->SetParent(a_pParent);
    return ptr.release();
  }

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

  //---------------------------------------------------------------------------
  void ParserTokenReader::SetVarCreator(facfun_type a_pFactory)
  {
    m_pFactory = a_pFactory;
  }

  //---------------------------------------------------------------------------
  /** \brief Return the current position of the token reader in the formula string. 

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

  //---------------------------------------------------------------------------
  /** \brief Return a reference to the formula. 

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

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

  //---------------------------------------------------------------------------
  /** \brief Initialize the token Reader. 
  
      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();
  }

  //---------------------------------------------------------------------------
  void ParserTokenReader::SetDefs( const funmap_type *a_pFunDef, 
                                   const funmap_type *a_pOprtDef,
                                   const funmap_type *a_pInfixOprtDef,
                                   const funmap_type *a_pPostOprtDef,
                                   varmap_type *a_pVarDef,
                                   const strmap_type *a_pStrVarDef,
                                   const valmap_type *a_pConstDef )
  {
    m_pFunDef = a_pFunDef;
    m_pOprtDef = a_pOprtDef;
    m_pInfixOprtDef = a_pInfixOprtDef;
    m_pPostOprtDef = a_pPostOprtDef;
    m_pVarDef = a_pVarDef;
    m_pStrVarDef = a_pStrVarDef;
    m_pConstDef = a_pConstDef;
  }

  //---------------------------------------------------------------------------
  /** \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. 
    otherwise it does. This variable is used internally only!
    It supresses a "undefined variable" exception in GetUsedVar().  
    Those function should return a complete list of variables including 
    those the are not defined by the time of it's call.
  */
  void ParserTokenReader::IgnoreUndefVar(bool bIgnore)
  {
    m_bIgnoreUndefVar = bIgnore;
  }

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

      The syntax flags will be reset to a value appropriate for the 
      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_UsedVar.clear();
  }

  //---------------------------------------------------------------------------
  /** \brief Read the next token from the string. */ 
  ParserTokenReader::token_type ParserTokenReader::ReadNextToken()
  {
    assert(m_pParser);

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

    while (szFormula[m_iPos]==' ') 
      ++m_iPos;

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

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

    // Check for unknown token
    // 
    // !!! From this point on there is no exit without an exception possible...
    // 
    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)
  {
    m_pParser  = a_pParent; 
    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.

    \param a_szCharSet [in] Const char array of the characters allowed in the token. 
    \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
  */
  int ParserTokenReader::ExtractToken( const char_type *a_szCharSet, 
                                       string_type &a_strTok, 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();  

    a_strTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd);
    a_iPos = iEnd;
    return iEnd;
  }

  //---------------------------------------------------------------------------
  /** \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 **pOprtDef = m_pParser->GetOprtDef();
    const char_type* 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::strlen( pOprtDef[i] );

      if (!std::strncmp(&szFormula[m_iPos], pOprtDef[i], len))
	    {
	      switch(i)
	      {
        case cmAND:
        case cmOR:
        case cmXOR:
        case cmLT:
		    case cmGT:
		    case cmLE:
		    case cmGE:
		    case cmNEQ:  
		    case cmEQ:
		    case cmADD:
		    case cmSUB:
		    case cmMUL:
		    case cmDIV:
		    case cmPOW:
        case cmASSIGN:
                      // The assignement operator need special treatment
                      if (i==cmASSIGN && m_iSynFlags & noASSIGN)
                        Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);

                      if (!m_pParser->HasBuiltInOprt()) continue;
                      if (m_iSynFlags & noOPT) 
                      {
                        // Maybe its an infix operator not an operator
                        // Both operator types can share characters in 
                        // their identifiers
                        if ( IsInfixOpTok(a_Tok) ) 
                          return true;

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

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

		    case cmCOMMA:
				              if (m_iSynFlags & noCOMMA)
					              Error(ecUNEXPECTED_COMMA, m_iPos, pOprtDef[i]);
        			
				              m_iSynFlags  = noBC | noOPT | noEND | noCOMMA | noPOSTOP | noASSIGN;
			                break;

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

				              m_iSynFlags = noBC | noOPT | noEND | noCOMMA | noPOSTOP | noASSIGN;
				              break;

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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -