/*************************************************************************************************** ** ** Original work Copyright (C) 2013 Ingo Berg ** Modified work Copyright 2014 Roman Telezhinsky ** ** 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. ** ******************************************************************************************************/ #ifndef QMUPARSERTOKEN_H #define QMUPARSERTOKEN_H #include #include #include #include #include #include "qmuparsererror.h" #include "qmuparsercallback.h" /** @file @brief This file contains the parser token definition. */ namespace qmu { /** @brief Encapsulation of the data for a single formula token. Formula token implementation. Part of the Math Parser Package. Formula tokens can be either one of the following:
  • value
  • variable
  • function with numerical arguments
  • functions with a string as argument
  • prefix operators
  • infix operators
  • binary operator
@author (C) 2004-2013 Ingo Berg */ template class QmuParserToken { private: ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode. ETypeCode m_iType; void *m_pTok; ///< Stores Token pointer; not applicable for all tokens int m_iIdx; ///< An otional index to an external buffer storing the token data TString m_strTok; ///< Token string TString m_strVal; ///< Value for string variables qreal m_fVal; ///< the value std::auto_ptr m_pCallback; public: //--------------------------------------------------------------------------- /** @brief Constructor (default). Sets token to an neutral state of type cmUNKNOWN. @throw nothrow @sa ECmdCode */ QmuParserToken() :m_iCode(cmUNKNOWN) ,m_iType(tpVOID) ,m_pTok(0) ,m_iIdx(-1) ,m_strTok() ,m_pCallback() {} //------------------------------------------------------------------------------ /** @brief Create token from another one. Implemented by calling Assign(...) @throw nothrow @post m_iType==cmUNKNOWN @sa #Assign */ QmuParserToken(const QmuParserToken &a_Tok) { Assign(a_Tok); } //------------------------------------------------------------------------------ /** @brief Assignement operator. Copy token state from another token and return this. Implemented by calling Assign(...). @throw nothrow */ QmuParserToken& operator=(const QmuParserToken &a_Tok) { Assign(a_Tok); return *this; } //------------------------------------------------------------------------------ /** @brief Copy token information from argument. @throw nothrow */ void Assign(const QmuParserToken &a_Tok) { m_iCode = a_Tok.m_iCode; m_pTok = a_Tok.m_pTok; m_strTok = a_Tok.m_strTok; m_iIdx = a_Tok.m_iIdx; m_strVal = a_Tok.m_strVal; m_iType = a_Tok.m_iType; m_fVal = a_Tok.m_fVal; // create new callback object if a_Tok has one m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0); } //------------------------------------------------------------------------------ /** @brief Assign a token type. Token may not be of type value, variable or function. Those have seperate set functions. \pre [assert] a_iType!=cmVAR \pre [assert] a_iType!=cmVAL \pre [assert] a_iType!=cmFUNC @post m_fVal = 0 @post m_pTok = 0 */ QmuParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString()) { // The following types cant be set this way, they have special Set functions assert(a_iType!=cmVAR); assert(a_iType!=cmVAL); assert(a_iType!=cmFUNC); m_iCode = a_iType; m_iType = tpVOID; m_pTok = 0; m_strTok = a_strTok; m_iIdx = -1; return *this; } //------------------------------------------------------------------------------ /** @brief Set Callback type. */ QmuParserToken& Set(const QmuParserCallback &a_pCallback, const TString &a_sTok) { assert(a_pCallback.GetAddr()); m_iCode = a_pCallback.GetCode(); m_iType = tpVOID; m_strTok = a_sTok; m_pCallback.reset(new QmuParserCallback(a_pCallback)); m_pTok = 0; m_iIdx = -1; return *this; } //------------------------------------------------------------------------------ /** @brief Make this token a value token. Member variables not necessary for value tokens will be invalidated. @throw nothrow */ QmuParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString()) { m_iCode = cmVAL; m_iType = tpDBL; m_fVal = a_fVal; m_strTok = a_strTok; m_iIdx = -1; m_pTok = 0; m_pCallback.reset(0); return *this; } //------------------------------------------------------------------------------ /** @brief make this token a variable token. Member variables not necessary for variable tokens will be invalidated. @throw nothrow */ QmuParserToken& SetVar(TBase *a_pVar, const TString &a_strTok) { m_iCode = cmVAR; m_iType = tpDBL; m_strTok = a_strTok; m_iIdx = -1; m_pTok = (void*)a_pVar; m_pCallback.reset(0); return *this; } //------------------------------------------------------------------------------ /** @brief Make this token a variable token. Member variables not necessary for variable tokens will be invalidated. @throw nothrow */ QmuParserToken& SetString(const TString &a_strTok, std::size_t a_iSize) { m_iCode = cmSTRING; m_iType = tpSTR; m_strTok = a_strTok; m_iIdx = static_cast(a_iSize); m_pTok = 0; m_pCallback.reset(0); return *this; } //------------------------------------------------------------------------------ /** @brief Set an index associated with the token related data. In cmSTRFUNC - This is the index to a string table in the main parser. * @param a_iIdx The index the string function result will take in the bytecode parser. @throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING */ void SetIdx(int a_iIdx) { if (m_iCode!=cmSTRING || a_iIdx<0) throw QmuParserError(ecINTERNAL_ERROR); m_iIdx = a_iIdx; } //------------------------------------------------------------------------------ /** @brief Return Index associated with the token related data. In cmSTRFUNC - This is the index to a string table in the main parser. @throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING * @return The index the result will take in the Bytecode calculatin array (#m_iIdx). */ int GetIdx() const { if (m_iIdx<0 || m_iCode!=cmSTRING ) throw QmuParserError(ecINTERNAL_ERROR); return m_iIdx; } //------------------------------------------------------------------------------ /** @brief Return the token type. * @return #m_iType @throw nothrow */ ECmdCode GetCode() const { if (m_pCallback.get()) { return m_pCallback->GetCode(); } else { return m_iCode; } } //------------------------------------------------------------------------------ ETypeCode GetType() const { if (m_pCallback.get()) { return m_pCallback->GetType(); } else { return m_iType; } } //------------------------------------------------------------------------------ int GetPri() const { if ( !m_pCallback.get()) throw QmuParserError(ecINTERNAL_ERROR); if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX) throw QmuParserError(ecINTERNAL_ERROR); return m_pCallback->GetPri(); } //------------------------------------------------------------------------------ EOprtAssociativity GetAssociativity() const { if (m_pCallback.get()==NULL || m_pCallback->GetCode()!=cmOPRT_BIN) throw QmuParserError(ecINTERNAL_ERROR); return m_pCallback->GetAssociativity(); } //------------------------------------------------------------------------------ /** @brief Return the address of the callback function assoziated with function and operator tokens. * @return The pointer stored in #m_pTok. @throw exception_type if token type is non of:
  • cmFUNC
  • cmSTRFUNC
  • cmPOSTOP
  • cmINFIXOP
  • cmOPRT_BIN
@sa ECmdCode */ generic_fun_type GetFuncAddr() const { return (m_pCallback.get()) ? (generic_fun_type)m_pCallback->GetAddr() : 0; } //------------------------------------------------------------------------------ /** \biref Get value of the token. Only applicable to variable and value tokens. @throw exception_type if token is no value/variable token. */ TBase GetVal() const { switch (m_iCode) { case cmVAL: return m_fVal; case cmVAR: return *((TBase*)m_pTok); default: throw QmuParserError(ecVAL_EXPECTED); } } //------------------------------------------------------------------------------ /** @brief Get address of a variable token. Valid only if m_iType==CmdVar. @throw exception_type if token is no variable token. */ TBase* GetVar() const { if (m_iCode!=cmVAR) throw QmuParserError(ecINTERNAL_ERROR); return (TBase*)m_pTok; } //------------------------------------------------------------------------------ /** @brief Return the number of function arguments. Valid only if m_iType==CmdFUNC. */ int GetArgCount() const { assert(m_pCallback.get()); if (!m_pCallback->GetAddr()) throw QmuParserError(ecINTERNAL_ERROR); return m_pCallback->GetArgc(); } //------------------------------------------------------------------------------ /** @brief Return the token identifier. If #m_iType is cmSTRING the token identifier is the value of the string argument for a string function. * @return #m_strTok @throw nothrow @sa m_strTok */ const TString& GetAsString() const { return m_strTok; } }; } // namespace qmu #endif