We don't need parser for integer value.

--HG--
branch : feature
This commit is contained in:
dismine 2014-04-26 10:51:14 +03:00
parent d8f0cc2824
commit 148d2fb3f7
5 changed files with 0 additions and 539 deletions

View file

@ -37,7 +37,6 @@ SOURCES += \
qmuparserbytecode.cpp \
qmuparserbase.cpp \
qmuparsertest.cpp \
qmuparserint.cpp \
stable.cpp
HEADERS += \
@ -52,7 +51,6 @@ HEADERS += \
qmuparserbytecode.h \
qmuparserbase.h \
qmuparsertest.h \
qmuparserint.h \
stable.h
VERSION = 2.2.3

View file

@ -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

View file

@ -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

View file

@ -214,79 +214,6 @@ namespace qmu
// 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);
// 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)
qmu::console() << "passed" << endl;
else
@ -1384,57 +1311,6 @@ namespace qmu
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. */
void QmuParserTester::Abort() const

View file

@ -27,7 +27,6 @@
#include <cstdlib>
#include <numeric> // for accumulate
#include "qmuparser.h"
#include "qmuparserint.h"
/** \file
\brief This file contains the parser test class.
@ -195,9 +194,6 @@ namespace qmu
double a_fRes2,
double a_fVar2);
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 qmu