2014-04-25 14:58:14 +02:00
|
|
|
/***************************************************************************************************
|
|
|
|
**
|
|
|
|
** Original work Copyright (C) 2013 Ingo Berg
|
|
|
|
** Modified work Copyright 2014 Roman Telezhinsky <dismine@gmail.com>
|
|
|
|
**
|
|
|
|
** 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>
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
#include <QStringList>
|
|
|
|
|
2014-04-25 14:58:14 +02:00
|
|
|
#include "qmuparsertokenreader.h"
|
|
|
|
#include "qmuparserbase.h"
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
\brief This file contains the parser token reader implementation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
namespace qmu
|
|
|
|
{
|
|
|
|
|
|
|
|
// Forward declaration
|
|
|
|
class QmuParserBase;
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Copy constructor.
|
|
|
|
|
|
|
|
\sa Assign
|
|
|
|
\throw nothrow
|
|
|
|
*/
|
|
|
|
QmuParserTokenReader::QmuParserTokenReader(const QmuParserTokenReader &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
|
|
|
|
*/
|
|
|
|
QmuParserTokenReader& QmuParserTokenReader::operator=(const QmuParserTokenReader &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 QmuParserTokenReader::Assign(const QmuParserTokenReader &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;
|
|
|
|
m_pFactoryData = a_Reader.m_pFactoryData;
|
|
|
|
m_iBrackets = a_Reader.m_iBrackets;
|
|
|
|
m_cArgSep = a_Reader.m_cArgSep;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \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.
|
|
|
|
*/
|
|
|
|
QmuParserTokenReader::QmuParserTokenReader(QmuParserBase *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);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Create instance of a QParserTokenReader 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 QParserTokenReader object.
|
|
|
|
\throw nothrow
|
|
|
|
*/
|
|
|
|
QmuParserTokenReader* QmuParserTokenReader::Clone(QmuParserBase *a_pParent) const
|
|
|
|
{
|
|
|
|
std::auto_ptr<QmuParserTokenReader> ptr(new QmuParserTokenReader(*this));
|
|
|
|
ptr->SetParent(a_pParent);
|
|
|
|
return ptr.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
QmuParserTokenReader::token_type& QmuParserTokenReader::SaveBeforeReturn(const token_type &tok)
|
|
|
|
{
|
|
|
|
m_lastTok = tok;
|
|
|
|
return m_lastTok;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void QmuParserTokenReader::AddValIdent(identfun_type a_pCallback)
|
|
|
|
{
|
|
|
|
// Use push_front is used to give user defined callbacks a higher priority than
|
|
|
|
// the built in ones. Otherwise reading hex numbers would not work
|
|
|
|
// since the "0" in "0xff" would always be read first making parsing of
|
|
|
|
// the rest impossible.
|
|
|
|
// reference:
|
|
|
|
// http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956
|
|
|
|
m_vIdentFun.push_front(a_pCallback);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void QmuParserTokenReader::SetVarCreator(facfun_type a_pFactory, void *pUserData)
|
|
|
|
{
|
|
|
|
m_pFactory = a_pFactory;
|
|
|
|
m_pFactoryData = pUserData;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Return the current position of the token reader in the formula string.
|
|
|
|
|
|
|
|
\return #m_iPos
|
|
|
|
\throw nothrow
|
|
|
|
*/
|
|
|
|
int QmuParserTokenReader::GetPos() const
|
|
|
|
{
|
|
|
|
return m_iPos;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Return a reference to the formula.
|
|
|
|
|
|
|
|
\return #m_strFormula
|
|
|
|
\throw nothrow
|
|
|
|
*/
|
2014-04-28 20:41:38 +02:00
|
|
|
const QString& QmuParserTokenReader::GetExpr() const
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
|
|
|
return m_strFormula;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Return a map containing the used variables only. */
|
|
|
|
varmap_type& QmuParserTokenReader::GetUsedVar()
|
|
|
|
{
|
|
|
|
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
|
|
|
|
*/
|
2014-04-28 20:41:38 +02:00
|
|
|
void QmuParserTokenReader::SetFormula(const QString &a_strFormula)
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
|
|
|
m_strFormula = a_strFormula;
|
|
|
|
ReInit();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \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 QmuParserTokenReader::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 QmuParserTokenReader::ReInit()
|
|
|
|
{
|
|
|
|
m_iPos = 0;
|
|
|
|
m_iSynFlags = sfSTART_OF_LINE;
|
|
|
|
m_iBrackets = 0;
|
|
|
|
m_UsedVar.clear();
|
|
|
|
m_lastTok = token_type();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Read the next token from the string. */
|
|
|
|
QmuParserTokenReader::token_type QmuParserTokenReader::ReadNextToken()
|
|
|
|
{
|
|
|
|
assert(m_pParser);
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
//std::stack<int> FunArgs;
|
|
|
|
#if defined(_UNICODE)
|
|
|
|
const char_type *szFormula = m_strFormula.toStdWString().c_str();
|
|
|
|
#else
|
|
|
|
const char_type *szFormula = m_strFormula.toStdString().c_str();
|
|
|
|
#endif
|
2014-04-25 14:58:14 +02:00
|
|
|
token_type tok;
|
|
|
|
|
|
|
|
// Ignore all non printable characters when reading the expression
|
|
|
|
while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20)
|
2014-04-28 20:41:38 +02:00
|
|
|
{
|
2014-04-25 14:58:14 +02:00
|
|
|
++m_iPos;
|
2014-04-28 20:41:38 +02:00
|
|
|
}
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
// 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 suppress the error for
|
|
|
|
// undefined variables in order to collect all variable
|
|
|
|
// names including the undefined ones.)
|
2014-04-28 20:41:38 +02:00
|
|
|
if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) )
|
|
|
|
{
|
2014-04-25 14:58:14 +02:00
|
|
|
return SaveBeforeReturn(tok);
|
2014-04-28 20:41:38 +02:00
|
|
|
}
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
// Check for unknown token
|
|
|
|
//
|
|
|
|
// !!! From this point on there is no exit without an exception possible...
|
|
|
|
//
|
2014-04-28 20:41:38 +02:00
|
|
|
QString strTok;
|
2014-04-25 14:58:14 +02:00
|
|
|
int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
|
|
|
|
if (iEnd!=m_iPos)
|
2014-04-28 20:41:38 +02:00
|
|
|
{
|
2014-04-25 14:58:14 +02:00
|
|
|
Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok);
|
2014-04-28 20:41:38 +02:00
|
|
|
}
|
2014-04-25 14:58:14 +02:00
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.mid(m_iPos));
|
2014-04-25 14:58:14 +02:00
|
|
|
return token_type(); // never reached
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void QmuParserTokenReader::SetParent(QmuParserBase *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;
|
|
|
|
}
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Extract all characters that belong to a certain charset.
|
2014-04-25 14:58:14 +02:00
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
\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 QmuParserTokenReader::ExtractToken(const QString &a_szCharSet, QString &a_sTok, int a_iPos) const
|
|
|
|
{
|
|
|
|
#if defined(_UNICODE)
|
|
|
|
const std::wstring m_strFormulaStd = m_strFormula.toStdWString();
|
|
|
|
const std::wstring a_szCharSetstd = a_szCharSet.toStdWString();
|
|
|
|
#else
|
|
|
|
const std::string m_strFormulaStd = m_strFormula.toStdString();
|
|
|
|
const std::string a_szCharSetStd = a_szCharSet.toStdString();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int iEnd = (int)m_strFormulaStd.find_first_not_of(a_szCharSetStd, a_iPos);
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
if (iEnd==(int)string_type::npos)
|
2014-04-28 20:41:38 +02:00
|
|
|
{
|
|
|
|
iEnd = (int)m_strFormulaStd.length();
|
|
|
|
}
|
|
|
|
|
2014-04-25 14:58:14 +02:00
|
|
|
// Assign token string if there was something found
|
|
|
|
if (a_iPos!=iEnd)
|
2014-04-28 20:41:38 +02:00
|
|
|
{
|
|
|
|
#if defined(_UNICODE)
|
|
|
|
a_sTok = QString().fromStdWString(std::wstring( m_strFormulaStd.begin()+a_iPos, m_strFormulaStd.begin()+iEnd));
|
|
|
|
#else
|
|
|
|
a_sTok = QString().fromStdString(std::string( m_strFormulaStd.begin()+a_iPos, m_strFormulaStd.begin()+iEnd));
|
|
|
|
#endif
|
|
|
|
}
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
return iEnd;
|
2014-04-28 20:41:38 +02:00
|
|
|
}
|
2014-04-25 14:58:14 +02:00
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Check Expression for the presence of a binary operator token.
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
int QmuParserTokenReader::ExtractOperatorToken(QString &a_sTok, int a_iPos) const
|
|
|
|
{
|
|
|
|
#if defined(_UNICODE)
|
|
|
|
const std::wstring m_strFormulaStd = m_strFormula.toStdWString();
|
|
|
|
const std::wstring oprtCharsStd = m_pParser->ValidInfixOprtChars().toStdWString();
|
|
|
|
#else
|
|
|
|
const std::string m_strFormulaStd = m_strFormula.toStdString();
|
|
|
|
const std::string oprtCharsStd = m_pParser->ValidInfixOprtChars().toStdString();
|
|
|
|
#endif
|
|
|
|
int iEnd = (int)m_strFormulaStd.find_first_not_of(oprtCharsStd, a_iPos);
|
2014-04-25 14:58:14 +02:00
|
|
|
if (iEnd==(int)string_type::npos)
|
2014-04-28 20:41:38 +02:00
|
|
|
{
|
|
|
|
iEnd = (int)m_strFormulaStd.length();
|
|
|
|
}
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
// Assign token string if there was something found
|
|
|
|
if (a_iPos!=iEnd)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
#if defined(_UNICODE)
|
|
|
|
a_sTok = QString().fromStdWString(string_type(m_strFormulaStd.begin() + a_iPos,
|
|
|
|
m_strFormulaStd.begin() + iEnd));
|
|
|
|
#else
|
|
|
|
a_sTok = QString().fromStdString(string_type(m_strFormulaStd.begin() + a_iPos, m_strFormulaStd.begin() + iEnd));
|
|
|
|
#endif
|
|
|
|
return iEnd;
|
2014-04-25 14:58:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
// There is still the chance of having to deal with an operator consisting exclusively
|
|
|
|
// of alphabetic characters.
|
|
|
|
return ExtractToken(QMUP_CHARS, a_sTok, a_iPos);
|
2014-04-25 14:58:14 +02:00
|
|
|
}
|
2014-04-28 20:41:38 +02:00
|
|
|
}
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \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 QmuParserTokenReader::IsBuiltIn(token_type &a_Tok)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
const QStringList pOprtDef = m_pParser->GetOprtDef();
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
// Compare token with function and operator strings
|
|
|
|
// check string for operator/function
|
2014-04-28 20:41:38 +02:00
|
|
|
for (int i=0; i < pOprtDef.size(); ++i)
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
int len = pOprtDef.at(i).length();
|
|
|
|
if ( pOprtDef.at(i) == m_strFormula.mid(m_iPos, m_iPos + len) )
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
|
|
|
switch(i)
|
|
|
|
{
|
|
|
|
//case cmAND:
|
|
|
|
//case cmOR:
|
|
|
|
//case cmXOR:
|
|
|
|
case cmLAND:
|
|
|
|
case cmLOR:
|
|
|
|
case cmLT:
|
|
|
|
case cmGT:
|
|
|
|
case cmLE:
|
|
|
|
case cmGE:
|
|
|
|
case cmNEQ:
|
|
|
|
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)
|
2014-04-28 20:41:38 +02:00
|
|
|
Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef.at(i));
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef.at(i));
|
2014-04-25 14:58:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE;
|
|
|
|
m_iSynFlags |= ( (i != cmEND) && ( i != cmBC) ) ? noEND : 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case cmBO:
|
|
|
|
if (m_iSynFlags & noBO)
|
2014-04-28 20:41:38 +02:00
|
|
|
Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef.at(i));
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
if (m_lastTok.GetCode()==cmFUNC)
|
|
|
|
m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE;
|
|
|
|
else
|
|
|
|
m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN| noIF | noELSE;
|
|
|
|
|
|
|
|
++m_iBrackets;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case cmBC:
|
|
|
|
if (m_iSynFlags & noBC)
|
2014-04-28 20:41:38 +02:00
|
|
|
Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef.at(i));
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN;
|
|
|
|
|
|
|
|
if (--m_iBrackets<0)
|
2014-04-28 20:41:38 +02:00
|
|
|
Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef.at(i));
|
2014-04-25 14:58:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case cmELSE:
|
|
|
|
if (m_iSynFlags & noELSE)
|
2014-04-28 20:41:38 +02:00
|
|
|
Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef.at(i));
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case cmIF:
|
|
|
|
if (m_iSynFlags & noIF)
|
2014-04-28 20:41:38 +02:00
|
|
|
Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef.at(i));
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing...
|
|
|
|
Error(ecINTERNAL_ERROR);
|
|
|
|
} // switch operator id
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
m_iPos += len;
|
|
|
|
a_Tok.Set( (ECmdCode)i, pOprtDef.at(i) );
|
2014-04-25 14:58:14 +02:00
|
|
|
return true;
|
|
|
|
} // if operator string found
|
|
|
|
} // end of for all operator strings
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool QmuParserTokenReader::IsArgSep(token_type &a_Tok)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
if (m_strFormula.at(m_iPos)==m_cArgSep)
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
|
|
|
// copy the separator into null terminated string
|
2014-04-28 20:41:38 +02:00
|
|
|
QString szSep;
|
2014-04-25 14:58:14 +02:00
|
|
|
szSep[0] = m_cArgSep;
|
|
|
|
szSep[1] = 0;
|
|
|
|
|
|
|
|
if (m_iSynFlags & noARG_SEP)
|
2014-04-28 20:41:38 +02:00
|
|
|
{
|
2014-04-25 14:58:14 +02:00
|
|
|
Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep);
|
2014-04-28 20:41:38 +02:00
|
|
|
}
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
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 QmuParserTokenReader::IsEOF(token_type &a_Tok)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
#if defined(_UNICODE)
|
|
|
|
const char_type* szFormula = m_strFormula.toStdWString().c_str();
|
|
|
|
#else
|
|
|
|
const char_type* szFormula = m_strFormula.toStdString().c_str();
|
|
|
|
#endif
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
// check for EOF
|
|
|
|
if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/)
|
|
|
|
{
|
|
|
|
if ( m_iSynFlags & noEND )
|
|
|
|
Error(ecUNEXPECTED_EOF, m_iPos);
|
|
|
|
|
|
|
|
if (m_iBrackets>0)
|
2014-04-25 17:01:23 +02:00
|
|
|
Error(ecMISSING_PARENS, m_iPos, ")");
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
m_iSynFlags = 0;
|
|
|
|
a_Tok.Set(cmEND);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Check if a string position contains a unary infix operator.
|
|
|
|
\return true if a function token has been found false otherwise.
|
|
|
|
*/
|
|
|
|
bool QmuParserTokenReader::IsInfixOpTok(token_type &a_Tok)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
QString sTok;
|
2014-04-25 14:58:14 +02:00
|
|
|
int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos);
|
|
|
|
if (iEnd==m_iPos)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// iteraterate over all postfix operator strings
|
|
|
|
funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin();
|
|
|
|
for ( ; it!=m_pInfixOprtDef->rend(); ++it)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
if (sTok.indexOf(it->first)!=0)
|
2014-04-25 14:58:14 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
a_Tok.Set(it->second, it->first);
|
|
|
|
m_iPos += (int)it->first.length();
|
|
|
|
|
|
|
|
if (m_iSynFlags & noINFIXOP)
|
|
|
|
Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
|
|
|
|
|
|
|
|
m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
a_Tok.Set(item->second, sTok);
|
|
|
|
m_iPos = (int)iEnd;
|
|
|
|
|
|
|
|
if (m_iSynFlags & noINFIXOP)
|
|
|
|
Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
|
|
|
|
|
|
|
|
m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN;
|
|
|
|
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 QmuParserTokenReader::IsFunTok(token_type &a_Tok)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
QString strTok;
|
2014-04-25 14:58:14 +02:00
|
|
|
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
|
2014-04-28 20:41:38 +02:00
|
|
|
if (m_strFormula.at(iEnd)!='(')
|
2014-04-25 14:58:14 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
a_Tok.Set(item->second, strTok);
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
m_iPos = iEnd;
|
2014-04-25 14:58:14 +02:00
|
|
|
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 QmuParserTokenReader::IsOprt(token_type &a_Tok)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
QString strTok;
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
int iEnd = ExtractOperatorToken(strTok, m_iPos);
|
|
|
|
if (iEnd==m_iPos)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check if the operator is a built in operator, if so ignore it here
|
2014-04-28 20:41:38 +02:00
|
|
|
const QStringList pOprtDef = m_pParser->GetOprtDef();
|
|
|
|
QStringList::const_iterator constIterator;
|
|
|
|
for (constIterator = pOprtDef.constBegin(); m_pParser->HasBuiltInOprt() && constIterator != pOprtDef.constEnd();
|
|
|
|
++constIterator)
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
if ((*constIterator)==strTok)
|
2014-04-25 14:58:14 +02:00
|
|
|
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
|
|
|
|
// are part of long token names (like: "add123") will be found instead
|
|
|
|
// 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)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
const QString &sID = it->first;
|
|
|
|
if ( sID == m_strFormula.mid(m_iPos, m_iPos + sID.length()) )
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
|
|
|
a_Tok.Set(it->second, strTok);
|
|
|
|
|
|
|
|
// operator was found
|
|
|
|
if (m_iSynFlags & noOPT)
|
|
|
|
{
|
|
|
|
// An operator was found but is not expected to occur at
|
|
|
|
// this position of the formula, maybe it is an infix
|
|
|
|
// operator, not a binary operator. Both operator types
|
|
|
|
// can share characters in their identifiers.
|
|
|
|
if ( IsInfixOpTok(a_Tok) )
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// nope, no infix operator
|
|
|
|
return false;
|
|
|
|
//Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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 QmuParserTokenReader::IsPostOpTok(token_type &a_Tok)
|
|
|
|
{
|
|
|
|
// <ibg 20110629> Do not check for postfix operators if they are not allowed at
|
|
|
|
// the current expression index.
|
|
|
|
//
|
|
|
|
// This will fix the bug reported here:
|
|
|
|
//
|
|
|
|
// http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979
|
|
|
|
//
|
|
|
|
if (m_iSynFlags & noPOSTOP)
|
|
|
|
return false;
|
|
|
|
// </ibg>
|
|
|
|
|
|
|
|
// Tricky problem with equations like "3m+5":
|
|
|
|
// m is a postfix operator, + is a valid sign for postfix operators and
|
|
|
|
// for binary operators parser detects "m+" as operator string and
|
|
|
|
// finds no matching postfix operator.
|
|
|
|
//
|
|
|
|
// This is a special case so this routine slightly differs from the other
|
|
|
|
// token readers.
|
|
|
|
|
|
|
|
// Test if there could be a postfix operator
|
2014-04-28 20:41:38 +02:00
|
|
|
QString sTok;
|
2014-04-25 14:58:14 +02:00
|
|
|
int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos);
|
|
|
|
if (iEnd==m_iPos)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// iteraterate over all postfix operator strings
|
|
|
|
funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin();
|
|
|
|
for ( ; it!=m_pPostOprtDef->rend(); ++it)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
if (sTok.indexOf(it->first)!=0)
|
2014-04-25 14:58:14 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
a_Tok.Set(it->second, sTok);
|
2014-04-28 20:41:38 +02:00
|
|
|
m_iPos += it->first.length();
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
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 QmuParserTokenReader::IsValTok(token_type &a_Tok)
|
|
|
|
{
|
|
|
|
assert(m_pConstDef);
|
|
|
|
assert(m_pParser);
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
QString strTok;
|
2014-04-25 17:01:23 +02:00
|
|
|
qreal fVal(0);
|
2014-04-25 14:58:14 +02:00
|
|
|
int iEnd(0);
|
|
|
|
|
|
|
|
// 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)
|
2014-04-28 20:41:38 +02:00
|
|
|
Error(ecUNEXPECTED_VAL, m_iPos - strTok.length(), strTok);
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3.call the value recognition functions provided by the user
|
|
|
|
// Call user defined value recognition functions
|
|
|
|
std::list<identfun_type>::const_iterator item = m_vIdentFun.begin();
|
|
|
|
for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item)
|
|
|
|
{
|
|
|
|
int iStart = m_iPos;
|
2014-04-28 20:41:38 +02:00
|
|
|
if ( (*item)(m_strFormula.mid(m_iPos), &m_iPos, &fVal)==1 )
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
strTok = m_strFormula.mid(iStart, m_iPos);
|
2014-04-25 14:58:14 +02:00
|
|
|
if (m_iSynFlags & noVAL)
|
2014-04-28 20:41:38 +02:00
|
|
|
Error(ecUNEXPECTED_VAL, m_iPos - strTok.length(), strTok);
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
a_Tok.SetVal(fVal, strTok);
|
|
|
|
m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Check wheter a token at a given position is a variable token.
|
|
|
|
\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 QmuParserTokenReader::IsVarTok(token_type &a_Tok)
|
|
|
|
{
|
|
|
|
if (!m_pVarDef->size())
|
|
|
|
return false;
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
QString strTok;
|
2014-04-25 14:58:14 +02:00
|
|
|
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():
|
|
|
|
// m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool QmuParserTokenReader::IsStrVarTok(token_type &a_Tok)
|
|
|
|
{
|
|
|
|
if (!m_pStrVarDef || !m_pStrVarDef->size())
|
|
|
|
return false;
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
QString strTok;
|
2014-04-25 14:58:14 +02:00
|
|
|
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 = noANY ^ ( noBC | noOPT | noEND | noARG_SEP);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
/** \brief Check wheter a token at a given position is an undefined variable.
|
|
|
|
|
|
|
|
\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 QmuParserTokenReader::IsUndefVarTok(token_type &a_Tok)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
QString strTok;
|
2014-04-25 14:58:14 +02:00
|
|
|
int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos) );
|
|
|
|
if ( iEnd==m_iPos )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (m_iSynFlags & noVAR)
|
|
|
|
{
|
|
|
|
// <ibg/> 20061021 added token string strTok instead of a_Tok.GetAsString() as the
|
|
|
|
// token identifier.
|
|
|
|
// 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)
|
|
|
|
{
|
2014-04-28 20:41:38 +02:00
|
|
|
qreal *fVar = m_pFactory(strTok, m_pFactoryData);
|
2014-04-25 14:58:14 +02:00
|
|
|
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
|
|
|
|
{
|
2014-04-25 17:01:23 +02:00
|
|
|
a_Tok.SetVar((qreal*)&m_fZero, strTok);
|
2014-04-25 14:58:14 +02:00
|
|
|
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 QmuParserTokenReader::IsString(token_type &a_Tok)
|
|
|
|
{
|
|
|
|
if (m_strFormula[m_iPos]!='"')
|
|
|
|
return false;
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
QString strBuf(m_strFormula[m_iPos+1]);
|
|
|
|
int iEnd(0), iSkip(0);
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
// parser over escaped '\"' end replace them with '"'
|
2014-04-28 20:41:38 +02:00
|
|
|
for(iEnd=strBuf.indexOf( "\"" ); iEnd!=0 && iEnd!=-1; iEnd=strBuf.indexOf( "\"", iEnd))
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
|
|
|
if (strBuf[iEnd-1]!='\\') break;
|
2014-04-25 17:01:23 +02:00
|
|
|
strBuf.replace(iEnd-1, 2, "\"" );
|
2014-04-25 14:58:14 +02:00
|
|
|
iSkip++;
|
|
|
|
}
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
if (iEnd==-1)
|
2014-04-25 17:01:23 +02:00
|
|
|
Error(ecUNTERMINATED_STRING, m_iPos, "\"" );
|
2014-04-25 14:58:14 +02:00
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
QString strTok = strBuf.mid(0, iEnd);
|
2014-04-25 14:58:14 +02:00
|
|
|
|
|
|
|
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());
|
|
|
|
|
2014-04-28 20:41:38 +02:00
|
|
|
m_iPos += (int)strTok.length() + 2 + iSkip; // +2 wg Anfhrungszeichen; +iSkip fr entfernte escape zeichen
|
2014-04-25 14:58:14 +02:00
|
|
|
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.
|
|
|
|
*/
|
|
|
|
void QmuParserTokenReader::Error( EErrorCodes a_iErrc,
|
|
|
|
int a_iPos,
|
2014-04-28 20:41:38 +02:00
|
|
|
const QString &a_sTok) const
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
|
|
|
m_pParser->Error(a_iErrc, a_iPos, a_sTok);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void QmuParserTokenReader::SetArgSep(char_type cArgSep)
|
|
|
|
{
|
|
|
|
m_cArgSep = cArgSep;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
2014-04-28 20:41:38 +02:00
|
|
|
QChar QmuParserTokenReader::GetArgSep() const
|
2014-04-25 14:58:14 +02:00
|
|
|
{
|
|
|
|
return m_cArgSep;
|
|
|
|
}
|
|
|
|
} // namespace qmu
|
|
|
|
|