We don't need parser for integer value.
--HG-- branch : feature
This commit is contained in:
parent
d8f0cc2824
commit
148d2fb3f7
|
@ -37,7 +37,6 @@ SOURCES += \
|
||||||
qmuparserbytecode.cpp \
|
qmuparserbytecode.cpp \
|
||||||
qmuparserbase.cpp \
|
qmuparserbase.cpp \
|
||||||
qmuparsertest.cpp \
|
qmuparsertest.cpp \
|
||||||
qmuparserint.cpp \
|
|
||||||
stable.cpp
|
stable.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
@ -52,7 +51,6 @@ HEADERS += \
|
||||||
qmuparserbytecode.h \
|
qmuparserbytecode.h \
|
||||||
qmuparserbase.h \
|
qmuparserbase.h \
|
||||||
qmuparsertest.h \
|
qmuparsertest.h \
|
||||||
qmuparserint.h \
|
|
||||||
stable.h
|
stable.h
|
||||||
|
|
||||||
VERSION = 2.2.3
|
VERSION = 2.2.3
|
||||||
|
|
|
@ -1,277 +0,0 @@
|
||||||
/***************************************************************************************************
|
|
||||||
**
|
|
||||||
** 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 "qmuparserint.h"
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <numeric>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
\brief Implementation of a parser using integer value.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \brief Namespace for mathematical applications. */
|
|
||||||
namespace qmu
|
|
||||||
{
|
|
||||||
qreal QmuParserInt::Abs(qreal v) { return (qreal)Round(fabs((double)v)); }
|
|
||||||
qreal QmuParserInt::Sign(qreal v) { return (Round(v)<0) ? -1 : (Round(v)>0) ? 1 : 0; }
|
|
||||||
qreal QmuParserInt::Ite(qreal v1,
|
|
||||||
qreal v2,
|
|
||||||
qreal v3) { return (Round(v1)==1) ? Round(v2) : Round(v3); }
|
|
||||||
qreal QmuParserInt::Add(qreal v1, qreal v2) { return Round(v1) + Round(v2); }
|
|
||||||
qreal QmuParserInt::Sub(qreal v1, qreal v2) { return Round(v1) - Round(v2); }
|
|
||||||
qreal QmuParserInt::Mul(qreal v1, qreal v2) { return Round(v1) * Round(v2); }
|
|
||||||
qreal QmuParserInt::Div(qreal v1, qreal v2) { return Round(v1) / Round(v2); }
|
|
||||||
qreal QmuParserInt::Mod(qreal v1, qreal v2) { return Round(v1) % Round(v2); }
|
|
||||||
qreal QmuParserInt::Shr(qreal v1, qreal v2) { return Round(v1) >> Round(v2); }
|
|
||||||
qreal QmuParserInt::Shl(qreal v1, qreal v2) { return Round(v1) << Round(v2); }
|
|
||||||
qreal QmuParserInt::LogAnd(qreal v1, qreal v2) { return Round(v1) & Round(v2); }
|
|
||||||
qreal QmuParserInt::LogOr(qreal v1, qreal v2) { return Round(v1) | Round(v2); }
|
|
||||||
qreal QmuParserInt::And(qreal v1, qreal v2) { return Round(v1) && Round(v2); }
|
|
||||||
qreal QmuParserInt::Or(qreal v1, qreal v2) { return Round(v1) || Round(v2); }
|
|
||||||
qreal QmuParserInt::Less(qreal v1, qreal v2) { return Round(v1) < Round(v2); }
|
|
||||||
qreal QmuParserInt::Greater(qreal v1, qreal v2) { return Round(v1) > Round(v2); }
|
|
||||||
qreal QmuParserInt::LessEq(qreal v1, qreal v2) { return Round(v1) <= Round(v2); }
|
|
||||||
qreal QmuParserInt::GreaterEq(qreal v1, qreal v2) { return Round(v1) >= Round(v2); }
|
|
||||||
qreal QmuParserInt::Equal(qreal v1, qreal v2) { return Round(v1) == Round(v2); }
|
|
||||||
qreal QmuParserInt::NotEqual(qreal v1, qreal v2) { return Round(v1) != Round(v2); }
|
|
||||||
qreal QmuParserInt::Not(qreal v) { return !Round(v); }
|
|
||||||
|
|
||||||
qreal QmuParserInt::Pow(qreal v1, qreal v2)
|
|
||||||
{
|
|
||||||
return std::pow((double)Round(v1), (double)Round(v2));
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
// Unary operator Callbacks: Infix operators
|
|
||||||
qreal QmuParserInt::UnaryMinus(qreal v)
|
|
||||||
{
|
|
||||||
return -Round(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
qreal QmuParserInt::Sum(const qreal* a_afArg, int a_iArgc)
|
|
||||||
{
|
|
||||||
if (!a_iArgc)
|
|
||||||
throw QmuParserError("too few arguments for function sum.");
|
|
||||||
|
|
||||||
qreal fRes=0;
|
|
||||||
for (int i=0; i<a_iArgc; ++i)
|
|
||||||
fRes += a_afArg[i];
|
|
||||||
|
|
||||||
return fRes;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
qreal QmuParserInt::Min(const qreal* a_afArg, int a_iArgc)
|
|
||||||
{
|
|
||||||
if (!a_iArgc)
|
|
||||||
throw QmuParserError( "too few arguments for function min." );
|
|
||||||
|
|
||||||
qreal fRes=a_afArg[0];
|
|
||||||
for (int i=0; i<a_iArgc; ++i)
|
|
||||||
fRes = std::min(fRes, a_afArg[i]);
|
|
||||||
|
|
||||||
return fRes;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
qreal QmuParserInt::Max(const qreal* a_afArg, int a_iArgc)
|
|
||||||
{
|
|
||||||
if (!a_iArgc)
|
|
||||||
throw QmuParserError("too few arguments for function min.");
|
|
||||||
|
|
||||||
qreal fRes=a_afArg[0];
|
|
||||||
for (int i=0; i<a_iArgc; ++i)
|
|
||||||
fRes = std::max(fRes, a_afArg[i]);
|
|
||||||
|
|
||||||
return fRes;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
// Default value recognition callback
|
|
||||||
int QmuParserInt::IsVal(const char_type *a_szExpr, int *a_iPos, qreal *a_fVal)
|
|
||||||
{
|
|
||||||
string_type buf(a_szExpr);
|
|
||||||
std::size_t pos = buf.find_first_not_of("0123456789");
|
|
||||||
|
|
||||||
if (pos==std::string::npos)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
stringstream_type stream( buf.substr(0, pos ) );
|
|
||||||
int iVal(0);
|
|
||||||
|
|
||||||
stream >> iVal;
|
|
||||||
if (stream.fail())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading
|
|
||||||
if (stream.fail())
|
|
||||||
iEnd = stream.str().length();
|
|
||||||
|
|
||||||
if (iEnd==(stringstream_type::pos_type)-1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
*a_iPos += (int)iEnd;
|
|
||||||
*a_fVal = (qreal)iVal;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
/** \brief Check a given position in the expression for the presence of
|
|
||||||
a hex value.
|
|
||||||
\param a_szExpr Pointer to the expression string
|
|
||||||
\param [in/out] a_iPos Pointer to an interger value holding the current parsing
|
|
||||||
position in the expression.
|
|
||||||
\param [out] a_fVal Pointer to the position where the detected value shall be stored.
|
|
||||||
|
|
||||||
Hey values must be prefixed with "0x" in order to be detected properly.
|
|
||||||
*/
|
|
||||||
int QmuParserInt::IsHexVal(const char_type *a_szExpr, int *a_iPos, qreal *a_fVal)
|
|
||||||
{
|
|
||||||
if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
unsigned iVal(0);
|
|
||||||
|
|
||||||
// New code based on streams for UNICODE compliance:
|
|
||||||
stringstream_type::pos_type nPos(0);
|
|
||||||
stringstream_type ss(a_szExpr + 2);
|
|
||||||
ss >> std::hex >> iVal;
|
|
||||||
nPos = ss.tellg();
|
|
||||||
|
|
||||||
if (nPos==(stringstream_type::pos_type)0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
*a_iPos += (int)(2 + nPos);
|
|
||||||
*a_fVal = (qreal)iVal;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
int QmuParserInt::IsBinVal(const char_type *a_szExpr, int *a_iPos, qreal *a_fVal)
|
|
||||||
{
|
|
||||||
if (a_szExpr[0]!='#')
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
unsigned iVal(0),
|
|
||||||
iBits(sizeof(iVal)*8),
|
|
||||||
i(0);
|
|
||||||
|
|
||||||
for (i=0; (a_szExpr[i+1]=='0' || a_szExpr[i+1]=='1') && i<iBits; ++i)
|
|
||||||
iVal |= (int)(a_szExpr[i+1]=='1') << ((iBits-1)-i);
|
|
||||||
|
|
||||||
if (i==0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (i==iBits)
|
|
||||||
throw exception_type("Binary to integer conversion error (overflow).");
|
|
||||||
|
|
||||||
*a_fVal = (unsigned)(iVal >> (iBits-i) );
|
|
||||||
*a_iPos += i+1;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
/** \brief Constructor.
|
|
||||||
|
|
||||||
Call ParserBase class constructor and trigger Function, Operator and Constant initialization.
|
|
||||||
*/
|
|
||||||
QmuParserInt::QmuParserInt()
|
|
||||||
:QmuParserBase()
|
|
||||||
{
|
|
||||||
AddValIdent(IsVal); // lowest priority
|
|
||||||
AddValIdent(IsBinVal);
|
|
||||||
AddValIdent(IsHexVal); // highest priority
|
|
||||||
|
|
||||||
InitCharSets();
|
|
||||||
InitFun();
|
|
||||||
InitOprt();
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void QmuParserInt::InitConst()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void QmuParserInt::InitCharSets()
|
|
||||||
{
|
|
||||||
DefineNameChars( "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" );
|
|
||||||
DefineOprtChars( "+-*^/?<>=!%&|~'_" );
|
|
||||||
DefineInfixOprtChars( "/+-*^?<>=!%&|~'_" );
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
/** \brief Initialize the default functions. */
|
|
||||||
void QmuParserInt::InitFun()
|
|
||||||
{
|
|
||||||
DefineFun( "sign", Sign);
|
|
||||||
DefineFun( "abs", Abs);
|
|
||||||
DefineFun( "if", Ite);
|
|
||||||
DefineFun( "sum", Sum);
|
|
||||||
DefineFun( "min", Min);
|
|
||||||
DefineFun( "max", Max);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
/** \brief Initialize operators. */
|
|
||||||
void QmuParserInt::InitOprt()
|
|
||||||
{
|
|
||||||
// disable all built in operators, not all of them usefull for integer numbers
|
|
||||||
// (they don't do rounding of values)
|
|
||||||
EnableBuiltInOprt(false);
|
|
||||||
|
|
||||||
// Disable all built in operators, they wont work with integer numbers
|
|
||||||
// since they are designed for floating point numbers
|
|
||||||
DefineInfixOprt( "-", UnaryMinus);
|
|
||||||
DefineInfixOprt( "!", Not);
|
|
||||||
|
|
||||||
DefineOprt( "&", LogAnd, prLOGIC);
|
|
||||||
DefineOprt( "|", LogOr, prLOGIC);
|
|
||||||
DefineOprt( "&&", And, prLOGIC);
|
|
||||||
DefineOprt( "||", Or, prLOGIC);
|
|
||||||
|
|
||||||
DefineOprt( "<", Less, prCMP);
|
|
||||||
DefineOprt( ">", Greater, prCMP);
|
|
||||||
DefineOprt( "<=", LessEq, prCMP);
|
|
||||||
DefineOprt( ">=", GreaterEq, prCMP);
|
|
||||||
DefineOprt( "==", Equal, prCMP);
|
|
||||||
DefineOprt( "!=", NotEqual, prCMP);
|
|
||||||
|
|
||||||
DefineOprt( "+", Add, prADD_SUB);
|
|
||||||
DefineOprt( "-", Sub, prADD_SUB);
|
|
||||||
|
|
||||||
DefineOprt( "*", Mul, prMUL_DIV);
|
|
||||||
DefineOprt( "/", Div, prMUL_DIV);
|
|
||||||
DefineOprt( "%", Mod, prMUL_DIV);
|
|
||||||
|
|
||||||
DefineOprt( "^", Pow, prPOW, oaRIGHT);
|
|
||||||
DefineOprt( ">>", Shr, prMUL_DIV+1);
|
|
||||||
DefineOprt( "<<", Shl, prMUL_DIV+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace qmu
|
|
|
@ -1,132 +0,0 @@
|
||||||
/***************************************************************************************************
|
|
||||||
**
|
|
||||||
** 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.
|
|
||||||
**
|
|
||||||
******************************************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QMUPARSERINT_H
|
|
||||||
#define QMUPARSERINT_H
|
|
||||||
|
|
||||||
#include "qmuparserbase.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
\brief Definition of a parser using integer value.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
namespace qmu
|
|
||||||
{
|
|
||||||
|
|
||||||
/** \brief Mathematical expressions parser.
|
|
||||||
|
|
||||||
This version of the parser handles only integer numbers. It disables the built in operators thus it is
|
|
||||||
slower than muParser. Integer values are stored in the double value_type and converted if needed.
|
|
||||||
*/
|
|
||||||
class QmuParserInt : public QmuParserBase
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
static int Round(qreal v) { return (int)(v + ((v>=0) ? 0.5 : -0.5) ); };
|
|
||||||
|
|
||||||
static qreal Abs(qreal);
|
|
||||||
static qreal Sign(qreal);
|
|
||||||
static qreal Ite(qreal, qreal, qreal);
|
|
||||||
// !! The unary Minus is a MUST, otherwise you cant use negative signs !!
|
|
||||||
static qreal UnaryMinus(qreal);
|
|
||||||
// Functions with variable number of arguments
|
|
||||||
static qreal Sum(const qreal* a_afArg, int a_iArgc); // sum
|
|
||||||
static qreal Min(const qreal* a_afArg, int a_iArgc); // minimum
|
|
||||||
static qreal Max(const qreal* a_afArg, int a_iArgc); // maximum
|
|
||||||
// binary operator callbacks
|
|
||||||
static qreal Add(qreal v1, qreal v2);
|
|
||||||
static qreal Sub(qreal v1, qreal v2);
|
|
||||||
static qreal Mul(qreal v1, qreal v2);
|
|
||||||
static qreal Div(qreal v1, qreal v2);
|
|
||||||
static qreal Mod(qreal v1, qreal v2);
|
|
||||||
static qreal Pow(qreal v1, qreal v2);
|
|
||||||
static qreal Shr(qreal v1, qreal v2);
|
|
||||||
static qreal Shl(qreal v1, qreal v2);
|
|
||||||
static qreal LogAnd(qreal v1, qreal v2);
|
|
||||||
static qreal LogOr(qreal v1, qreal v2);
|
|
||||||
static qreal And(qreal v1, qreal v2);
|
|
||||||
static qreal Or(qreal v1, qreal v2);
|
|
||||||
static qreal Xor(qreal v1, qreal v2);
|
|
||||||
static qreal Less(qreal v1, qreal v2);
|
|
||||||
static qreal Greater(qreal v1, qreal v2);
|
|
||||||
static qreal LessEq(qreal v1, qreal v2);
|
|
||||||
static qreal GreaterEq(qreal v1, qreal v2);
|
|
||||||
static qreal Equal(qreal v1, qreal v2);
|
|
||||||
static qreal NotEqual(qreal v1, qreal v2);
|
|
||||||
static qreal Not(qreal v1);
|
|
||||||
|
|
||||||
static int IsHexVal(const char_type* a_szExpr, int *a_iPos, qreal *a_iVal);
|
|
||||||
static int IsBinVal(const char_type* a_szExpr, int *a_iPos, qreal *a_iVal);
|
|
||||||
static int IsVal (const char_type* a_szExpr, int *a_iPos, qreal *a_iVal);
|
|
||||||
|
|
||||||
/** \brief A facet class used to change decimal and thousands separator. */
|
|
||||||
template<class TChar>
|
|
||||||
class change_dec_sep : public std::numpunct<TChar>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3)
|
|
||||||
:std::numpunct<TChar>()
|
|
||||||
,m_cDecPoint(cDecSep)
|
|
||||||
,m_cThousandsSep(cThousandsSep)
|
|
||||||
,m_nGroup(nGroup)
|
|
||||||
{}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
virtual char_type do_decimal_point() const
|
|
||||||
{
|
|
||||||
return m_cDecPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual char_type do_thousands_sep() const
|
|
||||||
{
|
|
||||||
return m_cThousandsSep;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::string do_grouping() const
|
|
||||||
{
|
|
||||||
return std::string(1, m_nGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
int m_nGroup;
|
|
||||||
char_type m_cDecPoint;
|
|
||||||
char_type m_cThousandsSep;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
QmuParserInt();
|
|
||||||
|
|
||||||
virtual void InitFun();
|
|
||||||
virtual void InitOprt();
|
|
||||||
virtual void InitConst();
|
|
||||||
virtual void InitCharSets();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace qmu
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -214,79 +214,6 @@ namespace qmu
|
||||||
// reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3
|
// reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3
|
||||||
iStat += EqnTest("3+4*2/(1-5)^2^3", 3.0001220703125, true);
|
iStat += EqnTest("3+4*2/(1-5)^2^3", 3.0001220703125, true);
|
||||||
|
|
||||||
// Test user defined binary operators
|
|
||||||
iStat += EqnTestInt("1 | 2", 3, true);
|
|
||||||
iStat += EqnTestInt("1 || 2", 1, true);
|
|
||||||
iStat += EqnTestInt("123 & 456", 72, true);
|
|
||||||
iStat += EqnTestInt("(123 & 456) % 10", 2, true);
|
|
||||||
iStat += EqnTestInt("1 && 0", 0, true);
|
|
||||||
iStat += EqnTestInt("123 && 456", 1, true);
|
|
||||||
iStat += EqnTestInt("1 << 3", 8, true);
|
|
||||||
iStat += EqnTestInt("8 >> 3", 1, true);
|
|
||||||
iStat += EqnTestInt("9 / 4", 2, true);
|
|
||||||
iStat += EqnTestInt("9 % 4", 1, true);
|
|
||||||
iStat += EqnTestInt("if(5%2,1,0)", 1, true);
|
|
||||||
iStat += EqnTestInt("if(4%2,1,0)", 0, true);
|
|
||||||
iStat += EqnTestInt("-10+1", -9, true);
|
|
||||||
iStat += EqnTestInt("1+2*3", 7, true);
|
|
||||||
iStat += EqnTestInt("const1 != const2", 1, true);
|
|
||||||
iStat += EqnTestInt("const1 != const2", 0, false);
|
|
||||||
iStat += EqnTestInt("const1 == const2", 0, true);
|
|
||||||
iStat += EqnTestInt("const1 == 1", 1, true);
|
|
||||||
iStat += EqnTestInt("10*(const1 == 1)", 10, true);
|
|
||||||
iStat += EqnTestInt("2*(const1 | const2)", 6, true);
|
|
||||||
iStat += EqnTestInt("2*(const1 | const2)", 7, false);
|
|
||||||
iStat += EqnTestInt("const1 < const2", 1, true);
|
|
||||||
iStat += EqnTestInt("const2 > const1", 1, true);
|
|
||||||
iStat += EqnTestInt("const1 <= 1", 1, true);
|
|
||||||
iStat += EqnTestInt("const2 >= 2", 1, true);
|
|
||||||
iStat += EqnTestInt("2*(const1 + const2)", 6, true);
|
|
||||||
iStat += EqnTestInt("2*(const1 - const2)", -2, true);
|
|
||||||
iStat += EqnTestInt("a != b", 1, true);
|
|
||||||
iStat += EqnTestInt("a != b", 0, false);
|
|
||||||
iStat += EqnTestInt("a == b", 0, true);
|
|
||||||
iStat += EqnTestInt("a == 1", 1, true);
|
|
||||||
iStat += EqnTestInt("10*(a == 1)", 10, true);
|
|
||||||
iStat += EqnTestInt("2*(a | b)", 6, true);
|
|
||||||
iStat += EqnTestInt("2*(a | b)", 7, false);
|
|
||||||
iStat += EqnTestInt("a < b", 1, true);
|
|
||||||
iStat += EqnTestInt("b > a", 1, true);
|
|
||||||
iStat += EqnTestInt("a <= 1", 1, true);
|
|
||||||
iStat += EqnTestInt("b >= 2", 1, true);
|
|
||||||
iStat += EqnTestInt("2*(a + b)", 6, true);
|
|
||||||
iStat += EqnTestInt("2*(a - b)", -2, true);
|
|
||||||
iStat += EqnTestInt("a + (a << b)", 5, true);
|
|
||||||
iStat += EqnTestInt("-2^2", -4, true);
|
|
||||||
iStat += EqnTestInt("3--a", 4, true);
|
|
||||||
iStat += EqnTestInt("3+-3^2", -6, true);
|
|
||||||
|
|
||||||
// Test reading of hex values:
|
|
||||||
iStat += EqnTestInt("0xff", 255, true);
|
|
||||||
iStat += EqnTestInt("10+0xff", 265, true);
|
|
||||||
iStat += EqnTestInt("0xff+10", 265, true);
|
|
||||||
iStat += EqnTestInt("10*0xff", 2550, true);
|
|
||||||
iStat += EqnTestInt("0xff*10", 2550, true);
|
|
||||||
iStat += EqnTestInt("10+0xff+1", 266, true);
|
|
||||||
iStat += EqnTestInt("1+0xff+10", 266, true);
|
|
||||||
|
|
||||||
// incorrect: '^' is your here, not power
|
|
||||||
// iStat += EqnTestInt("-(1+2)^2", -9, true);
|
|
||||||
// iStat += EqnTestInt("-1^3", -1, true);
|
|
||||||
|
|
||||||
// Test precedence
|
|
||||||
// a=1, b=2, c=3
|
|
||||||
iStat += EqnTestInt("a + b * c", 7, true);
|
|
||||||
iStat += EqnTestInt("a * b + c", 5, true);
|
|
||||||
iStat += EqnTestInt("a<b && b>10", 0, true);
|
|
||||||
iStat += EqnTestInt("a<b && b<10", 1, true);
|
|
||||||
|
|
||||||
iStat += EqnTestInt("a + b << c", 17, true);
|
|
||||||
iStat += EqnTestInt("a << b + c", 7, true);
|
|
||||||
iStat += EqnTestInt("c * b < a", 0, true);
|
|
||||||
iStat += EqnTestInt("c * b == 6 * a", 1, true);
|
|
||||||
iStat += EqnTestInt("2^2^3", 256, true);
|
|
||||||
|
|
||||||
|
|
||||||
if (iStat==0)
|
if (iStat==0)
|
||||||
qmu::console() << "passed" << endl;
|
qmu::console() << "passed" << endl;
|
||||||
else
|
else
|
||||||
|
@ -1384,57 +1311,6 @@ namespace qmu
|
||||||
return iRet;
|
return iRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
int QmuParserTester::EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass)
|
|
||||||
{
|
|
||||||
QmuParserTester::c_iCount++;
|
|
||||||
|
|
||||||
qreal vVarVal[] = {1, 2, 3}; // variable values
|
|
||||||
qreal fVal[2] = {-99, -999}; // results: initially should be different
|
|
||||||
int iRet(0);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
QmuParserInt p;
|
|
||||||
p.DefineConst( "const1", 1);
|
|
||||||
p.DefineConst( "const2", 2);
|
|
||||||
p.DefineVar( "a", &vVarVal[0]);
|
|
||||||
p.DefineVar( "b", &vVarVal[1]);
|
|
||||||
p.DefineVar( "c", &vVarVal[2]);
|
|
||||||
|
|
||||||
p.SetExpr(a_str);
|
|
||||||
fVal[0] = p.Eval(); // result from stringparsing
|
|
||||||
fVal[1] = p.Eval(); // result from bytecode
|
|
||||||
|
|
||||||
if (fVal[0]!=fVal[1])
|
|
||||||
throw QmuParser::exception_type( "Bytecode corrupt." );
|
|
||||||
|
|
||||||
iRet = ( (a_fRes==fVal[0] && a_fPass) ||
|
|
||||||
(a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1;
|
|
||||||
if (iRet==1)
|
|
||||||
{
|
|
||||||
qmu::console() << "\n fail: " << a_str.c_str()
|
|
||||||
<< " (incorrect result; expected: " << a_fRes
|
|
||||||
<< " ;calculated: " << fVal[0]<< ").";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(QmuParser::exception_type &e)
|
|
||||||
{
|
|
||||||
if (a_fPass)
|
|
||||||
{
|
|
||||||
qmu::console() << "\n fail: " << e.GetExpr() << " : " << e.GetMsg();
|
|
||||||
iRet = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
qmu::console() << "\n fail: " << a_str.c_str() << " (unexpected exception)";
|
|
||||||
iRet = 1; // exceptions other than ParserException are not allowed
|
|
||||||
}
|
|
||||||
|
|
||||||
return iRet;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
/** \brief Internal error in test class Test is going to be aborted. */
|
/** \brief Internal error in test class Test is going to be aborted. */
|
||||||
void QmuParserTester::Abort() const
|
void QmuParserTester::Abort() const
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <numeric> // for accumulate
|
#include <numeric> // for accumulate
|
||||||
#include "qmuparser.h"
|
#include "qmuparser.h"
|
||||||
#include "qmuparserint.h"
|
|
||||||
|
|
||||||
/** \file
|
/** \file
|
||||||
\brief This file contains the parser test class.
|
\brief This file contains the parser test class.
|
||||||
|
@ -195,9 +194,6 @@ namespace qmu
|
||||||
double a_fRes2,
|
double a_fRes2,
|
||||||
double a_fVar2);
|
double a_fVar2);
|
||||||
int ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail = true);
|
int ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail = true);
|
||||||
|
|
||||||
// Test Int Parser
|
|
||||||
int EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass);
|
|
||||||
};
|
};
|
||||||
} // namespace Test
|
} // namespace Test
|
||||||
} // namespace qmu
|
} // namespace qmu
|
||||||
|
|
Loading…
Reference in New Issue
Block a user