Use Qt math function.

--HG--
branch : feature
This commit is contained in:
dismine 2014-04-26 10:23:50 +03:00
parent 59c7405b88
commit 21c38b446d
9 changed files with 213 additions and 419 deletions

View file

@ -21,7 +21,8 @@
******************************************************************************************************/
#include "qmuparser.h"
#include "qmuparsertemplatemagic.h"
#include <QtMath>
#include <QtGlobal>
//--- Standard includes ------------------------------------------------------------------------
#include <cmath>
@ -40,28 +41,17 @@ using namespace std;
\brief Implementation of the standard floating point QmuParser.
*/
/** \brief Namespace for mathematical applications. */
namespace qmu
{
//---------------------------------------------------------------------------
// Trigonometric function
qreal QmuParser::Sin(qreal v) { return MathImpl<qreal>::Sin(v); }
qreal QmuParser::Cos(qreal v) { return MathImpl<qreal>::Cos(v); }
qreal QmuParser::Tan(qreal v) { return MathImpl<qreal>::Tan(v); }
qreal QmuParser::ASin(qreal v) { return MathImpl<qreal>::ASin(v); }
qreal QmuParser::ACos(qreal v) { return MathImpl<qreal>::ACos(v); }
qreal QmuParser::ATan(qreal v) { return MathImpl<qreal>::ATan(v); }
qreal QmuParser::ATan2(qreal v1, qreal v2) { return MathImpl<qreal>::ATan2(v1, v2); }
qreal QmuParser::Sinh(qreal v) { return MathImpl<qreal>::Sinh(v); }
qreal QmuParser::Cosh(qreal v) { return MathImpl<qreal>::Cosh(v); }
qreal QmuParser::Tanh(qreal v) { return MathImpl<qreal>::Tanh(v); }
qreal QmuParser::ASinh(qreal v) { return MathImpl<qreal>::ASinh(v); }
qreal QmuParser::ACosh(qreal v) { return MathImpl<qreal>::ACosh(v); }
qreal QmuParser::ATanh(qreal v) { return MathImpl<qreal>::ATanh(v); }
qreal QmuParser::Sinh(qreal v) { return sinh(v); }
qreal QmuParser::Cosh(qreal v) { return cosh(v); }
qreal QmuParser::Tanh(qreal v) { return tanh(v); }
qreal QmuParser::ASinh(qreal v) { return log(v + qSqrt(v * v + 1)); }
qreal QmuParser::ACosh(qreal v) { return log(v + qSqrt(v * v - 1)); }
qreal QmuParser::ATanh(qreal v) { return ((qreal)0.5 * log((1 + v) / (1 - v))); }
//---------------------------------------------------------------------------
// Logarithm functions
@ -74,7 +64,7 @@ namespace qmu
throw QmuParserError(ecDOMAIN_ERROR, "Log2");
#endif
return MathImpl<qreal>::Log2(v);
return log(v)/log((qreal)2);
}
// Logarithm base 10
@ -85,35 +75,14 @@ namespace qmu
throw QmuParserError(ecDOMAIN_ERROR, "Log10");
#endif
return MathImpl<qreal>::Log10(v);
}
// Logarithm base e (natural logarithm)
qreal QmuParser::Ln(qreal v)
{
#ifdef MUP_MATH_EXCEPTIONS
if (v<=0)
throw QmuParserError(ecDOMAIN_ERROR, "Ln");
#endif
return MathImpl<qreal>::Log(v);
return log10(v);
}
//---------------------------------------------------------------------------
// misc
qreal QmuParser::Exp(qreal v) { return MathImpl<qreal>::Exp(v); }
qreal QmuParser::Abs(qreal v) { return MathImpl<qreal>::Abs(v); }
qreal QmuParser::Sqrt(qreal v)
{
#ifdef MUP_MATH_EXCEPTIONS
if (v<0)
throw QmuParserError(ecDOMAIN_ERROR, "sqrt");
#endif
return MathImpl<qreal>::Sqrt(v);
}
qreal QmuParser::Rint(qreal v) { return MathImpl<qreal>::Rint(v); }
qreal QmuParser::Sign(qreal v) { return MathImpl<qreal>::Sign(v); }
qreal QmuParser::Abs(qreal v) { return (v>=0) ? v : -v; }
qreal QmuParser::Rint(qreal v) { return qFloor(v + (qreal)0.5); }
qreal QmuParser::Sign(qreal v) { return (qreal)((v<0) ? -1 : (v>0) ? 1 : 0); }
//---------------------------------------------------------------------------
/** \brief Callback for the unary minus operator.
@ -156,39 +125,45 @@ namespace qmu
}
//---------------------------------------------------------------------------
/** \brief Callback for determining the minimum value out of a vector.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
qreal QmuParser::Min(const qreal *a_afArg, int a_iArgc)
{
//---------------------------------------------------------------------------
/** \brief Callback for determining the minimum value out of a vector.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
qreal QmuParser::Min(const qreal *a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw exception_type("too few arguments for function min.");
{
throw exception_type("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]);
{
fRes = qMin(fRes, a_afArg[i]);
}
return fRes;
}
}
//---------------------------------------------------------------------------
/** \brief Callback for determining the maximum value out of a vector.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
qreal QmuParser::Max(const qreal *a_afArg, int a_iArgc)
{
//---------------------------------------------------------------------------
/** \brief Callback for determining the maximum value out of a vector.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
qreal QmuParser::Max(const qreal *a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw exception_type("too few arguments for function min.");
{
throw exception_type("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]);
for (int i=0; i<a_iArgc; ++i)
{
fRes = qMax(fRes, a_afArg[i]);
}
return fRes;
}
}
//---------------------------------------------------------------------------
@ -247,55 +222,44 @@ namespace qmu
DefineInfixOprtChars( "/+-*^?<>=#!$%&|~'_" );
}
//---------------------------------------------------------------------------
/** \brief Initialize the default functions. */
void QmuParser::InitFun()
{
if (qmu::TypeInfo<qreal>::IsInteger())
{
// When setting MUP_BASETYPE to an integer type
// Place functions for dealing with integer values here
// ...
// ...
// ...
}
else
{
// trigonometric functions
DefineFun("sin", Sin);
DefineFun("cos", Cos);
DefineFun("tan", Tan);
// arcus functions
DefineFun("asin", ASin);
DefineFun("acos", ACos);
DefineFun("atan", ATan);
DefineFun("atan2", ATan2);
// hyperbolic functions
DefineFun("sinh", Sinh);
DefineFun("cosh", Cosh);
DefineFun("tanh", Tanh);
// arcus hyperbolic functions
DefineFun("asinh", ASinh);
DefineFun("acosh", ACosh);
DefineFun("atanh", ATanh);
// Logarithm functions
DefineFun("log2", Log2);
DefineFun("log10", Log10);
DefineFun("log", Log10);
DefineFun("ln", Ln);
// misc
DefineFun("exp", Exp);
DefineFun("sqrt", Sqrt);
DefineFun("sign", Sign);
DefineFun("rint", Rint);
DefineFun("abs", Abs);
// Functions with variable number of arguments
DefineFun("sum", Sum);
DefineFun("avg", Avg);
DefineFun("min", Min);
DefineFun("max", Max);
}
}
//---------------------------------------------------------------------------
/** \brief Initialize the default functions. */
void QmuParser::InitFun()
{
// trigonometric functions
DefineFun("sin", qSin);
DefineFun("cos", qCos);
DefineFun("tan", qTan);
// arcus functions
DefineFun("asin", qAsin);
DefineFun("acos", qAcos);
DefineFun("atan", qAtan);
DefineFun("atan2", qAtan2);
// hyperbolic functions
DefineFun("sinh", Sinh);
DefineFun("cosh", Cosh);
DefineFun("tanh", Tanh);
// arcus hyperbolic functions
DefineFun("asinh", ASinh);
DefineFun("acosh", ACosh);
DefineFun("atanh", ATanh);
// Logarithm functions
DefineFun("log2", Log2);
DefineFun("log10", Log10);
DefineFun("log", Log10);
DefineFun("ln", qLn);
// misc
DefineFun("exp", qExp);
DefineFun("sqrt", qSqrt);
DefineFun("sign", Sign);
DefineFun("rint", Rint);
DefineFun("abs", Abs);
// Functions with variable number of arguments
DefineFun("sum", Sum);
DefineFun("avg", Avg);
DefineFun("min", Min);
DefineFun("max", Max);
}
//---------------------------------------------------------------------------
/** \brief Initialize constants.

View file

@ -30,7 +30,6 @@
//--- Parser includes --------------------------------------------------------------------------
#include "qmuparserbase.h"
#include "qmuparsertemplatemagic.h"
/** \file
\brief Definition of the standard floating point parser.
@ -61,18 +60,8 @@ public:
qreal Diff(qreal *a_Var, qreal a_fPos, qreal a_fEpsilon = 0) const;
protected:
// Trigonometric functions
static qreal Sin(qreal);
static qreal Cos(qreal);
static qreal Tan(qreal);
static qreal Tan2(qreal, qreal);
// arcus functions
static qreal ASin(qreal);
static qreal ACos(qreal);
static qreal ATan(qreal);
static qreal ATan2(qreal, qreal);
// hyperbolic functions
static qreal Sinh(qreal);
static qreal Cosh(qreal);
@ -84,18 +73,13 @@ protected:
// Logarithm functions
static qreal Log2(qreal); // Logarithm Base 2
static qreal Log10(qreal); // Logarithm Base 10
static qreal Ln(qreal); // Logarithm Base e (natural logarithm)
// misc
static qreal Exp(qreal);
static qreal Abs(qreal);
static qreal Sqrt(qreal);
static qreal Rint(qreal);
static qreal Sign(qreal);
// Prefix operators
// !!! Unary Minus is a MUST if you want to use negative signs !!!
static qreal UnaryMinus(qreal);
// Functions with variable number of arguments
static qreal Sum(const qreal*, int); // sum
static qreal Avg(const qreal*, int); // mean value

View file

@ -52,7 +52,6 @@ HEADERS += \
qmuparserbytecode.h \
qmuparserbase.h \
qmuparsertest.h \
qmuparsertemplatemagic.h \
qmuparserint.h \
stable.h

View file

@ -21,7 +21,6 @@
******************************************************************************************************/
#include "qmuparserbase.h"
#include "qmuparsertemplatemagic.h"
//--- Standard includes ------------------------------------------------------------------------
#include <cassert>
@ -266,11 +265,11 @@ namespace qmu
stringstream_type ss;
ss << MUP_VERSION;
ss << QMUP_VERSION;
if (eInfo==pviFULL)
{
ss << " (" << MUP_VERSION_DATE;
ss << " (" << QMUP_VERSION_DATE;
ss << std::dec << "; " << sizeof(void*)*8 << "BIT";
#ifdef _DEBUG
@ -1030,7 +1029,7 @@ void QmuParserBase::SetExpr(const string_type &a_sExpr)
continue;
case cmPOW:
--sidx; Stack[sidx] = MathImpl<qreal>::Pow(Stack[sidx], Stack[1+sidx]);
--sidx; Stack[sidx] = std::pow(Stack[sidx], Stack[1+sidx]);
continue;
case cmLAND: --sidx; Stack[sidx] = Stack[sidx] && Stack[sidx+1]; continue;
@ -1607,22 +1606,22 @@ void QmuParserBase::SetExpr(const string_type &a_sExpr)
QStack<token_type> stOprt(a_stOprt),
stVal(a_stVal);
mu::console() << "\nValue stack:\n";
qmu::console() << "\nValue stack:\n";
while ( !stVal.empty() )
{
token_type val = stVal.pop();
if (val.GetType()==tpSTR)
mu::console() << " \"" << val.GetAsString() << "\" ";
qmu::console() << " \"" << val.GetAsString() << "\" ";
else
mu::console() << " " << val.GetVal() << " ";
qmu::console() << " " << val.GetVal() << " ";
}
mu::console() << "\nOperator stack:\n";
qmu::console() << "\nOperator stack:\n";
while ( !stOprt.empty() )
{
if (stOprt.top().GetCode()<=cmASSIGN)
{
mu::console() << "OPRT_INTRNL \""
qmu::console() << "OPRT_INTRNL \""
<< QmuParserBase::c_DefaultOprt[stOprt.top().GetCode()]
<< "\" \n";
}
@ -1630,35 +1629,35 @@ void QmuParserBase::SetExpr(const string_type &a_sExpr)
{
switch(stOprt.top().GetCode())
{
case cmVAR: mu::console() << "VAR\n"; break;
case cmVAL: mu::console() << "VAL\n"; break;
case cmFUNC: mu::console() << "FUNC \""
case cmVAR: qmu::console() << "VAR\n"; break;
case cmVAL: qmu::console() << "VAL\n"; break;
case cmFUNC: qmu::console() << "FUNC \""
<< stOprt.top().GetAsString()
<< "\"\n"; break;
case cmFUNC_BULK: mu::console() << "FUNC_BULK \""
case cmFUNC_BULK: qmu::console() << "FUNC_BULK \""
<< stOprt.top().GetAsString()
<< "\"\n"; break;
case cmOPRT_INFIX: mu::console() << "OPRT_INFIX \""
case cmOPRT_INFIX: qmu::console() << "OPRT_INFIX \""
<< stOprt.top().GetAsString()
<< "\"\n"; break;
case cmOPRT_BIN: mu::console() << "OPRT_BIN \""
case cmOPRT_BIN: qmu::console() << "OPRT_BIN \""
<< stOprt.top().GetAsString()
<< "\"\n"; break;
case cmFUNC_STR: mu::console() << "FUNC_STR\n"; break;
case cmEND: mu::console() << "END\n"; break;
case cmUNKNOWN: mu::console() << "UNKNOWN\n"; break;
case cmBO: mu::console() << "BRACKET \"(\"\n"; break;
case cmBC: mu::console() << "BRACKET \")\"\n"; break;
case cmIF: mu::console() << "IF\n"; break;
case cmELSE: mu::console() << "ELSE\n"; break;
case cmENDIF: mu::console() << "ENDIF\n"; break;
default: mu::console() << stOprt.top().GetCode() << " "; break;
case cmFUNC_STR: qmu::console() << "FUNC_STR\n"; break;
case cmEND: qmu::console() << "END\n"; break;
case cmUNKNOWN: qmu::console() << "UNKNOWN\n"; break;
case cmBO: qmu::console() << "BRACKET \"(\"\n"; break;
case cmBC: qmu::console() << "BRACKET \")\"\n"; break;
case cmIF: qmu::console() << "IF\n"; break;
case cmELSE: qmu::console() << "ELSE\n"; break;
case cmENDIF: qmu::console() << "ENDIF\n"; break;
default: qmu::console() << stOprt.top().GetCode() << " "; break;
}
}
stOprt.pop();
}
mu::console() << dec << endl;
qmu::console() << dec << endl;
}
//------------------------------------------------------------------------------

View file

@ -34,7 +34,6 @@
//--- Parser includes --------------------------------------------------------------------------
#include "qmuparserdef.h"
#include "qmuparserstack.h"
#include "qmuparsertokenreader.h"
#include "qmuparserbytecode.h"
#include "qmuparsererror.h"
@ -121,7 +120,7 @@ private:
bool HasBuiltInOprt() const;
void AddValIdent(identfun_type a_pCallback);
/** \fn void mu::QParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt = true)
/** \fn void qmu::QmuParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt = true)
\brief Define a parser function without arguments.
\param a_strName Name of the function
\param a_pFun Pointer to the callback function

View file

@ -31,8 +31,6 @@
#include "qmuparserdef.h"
#include "qmuparsererror.h"
#include "qmuparsertoken.h"
#include "qmuparserstack.h"
#include "qmuparsertemplatemagic.h"
namespace qmu
@ -166,7 +164,7 @@ namespace qmu
m_vRPN.pop_back();
break;
case cmPOW: x = MathImpl<qreal>::Pow(x, y);
case cmPOW: x = std::pow(x, y);
m_vRPN.pop_back();
break;
@ -495,89 +493,89 @@ namespace qmu
{
if (!m_vRPN.size())
{
mu::console() << "No bytecode available\n";
qmu::console() << "No bytecode available\n";
return;
}
mu::console() << "Number of RPN tokens:" << (int)m_vRPN.size() << "\n";
qmu::console() << "Number of RPN tokens:" << (int)m_vRPN.size() << "\n";
for (std::size_t i=0; i<m_vRPN.size() && m_vRPN[i].Cmd!=cmEND; ++i)
{
mu::console() << std::dec << i << " : \t";
qmu::console() << std::dec << i << " : \t";
switch (m_vRPN[i].Cmd)
{
case cmVAL: mu::console() << "VAL \t";
mu::console() << "[" << m_vRPN[i].Val.data2 << "]\n";
case cmVAL: qmu::console() << "VAL \t";
qmu::console() << "[" << m_vRPN[i].Val.data2 << "]\n";
break;
case cmVAR: mu::console() << "VAR \t";
mu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Val.ptr << "]\n";
case cmVAR: qmu::console() << "VAR \t";
qmu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Val.ptr << "]\n";
break;
case cmVARPOW2: mu::console() << "VARPOW2 \t";
mu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Val.ptr << "]\n";
case cmVARPOW2: qmu::console() << "VARPOW2 \t";
qmu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Val.ptr << "]\n";
break;
case cmVARPOW3: mu::console() << "VARPOW3 \t";
mu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Val.ptr << "]\n";
case cmVARPOW3: qmu::console() << "VARPOW3 \t";
qmu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Val.ptr << "]\n";
break;
case cmVARPOW4: mu::console() << "VARPOW4 \t";
mu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Val.ptr << "]\n";
case cmVARPOW4: qmu::console() << "VARPOW4 \t";
qmu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Val.ptr << "]\n";
break;
case cmVARMUL: mu::console() << "VARMUL \t";
mu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Val.ptr << "]";
mu::console() << " * [" << m_vRPN[i].Val.data << "]";
mu::console() << " + [" << m_vRPN[i].Val.data2 << "]\n";
case cmVARMUL: qmu::console() << "VARMUL \t";
qmu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Val.ptr << "]";
qmu::console() << " * [" << m_vRPN[i].Val.data << "]";
qmu::console() << " + [" << m_vRPN[i].Val.data2 << "]\n";
break;
case cmFUNC: mu::console() << "CALL\t";
mu::console() << "[ARG:" << std::dec << m_vRPN[i].Fun.argc << "]";
mu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Fun.ptr << "]";
mu::console() << "\n";
case cmFUNC: qmu::console() << "CALL\t";
qmu::console() << "[ARG:" << std::dec << m_vRPN[i].Fun.argc << "]";
qmu::console() << "[ADDR: 0x" << std::hex << m_vRPN[i].Fun.ptr << "]";
qmu::console() << "\n";
break;
case cmFUNC_STR:
mu::console() << "CALL STRFUNC\t";
mu::console() << "[ARG:" << std::dec << m_vRPN[i].Fun.argc << "]";
mu::console() << "[IDX:" << std::dec << m_vRPN[i].Fun.idx << "]";
mu::console() << "[ADDR: 0x" << m_vRPN[i].Fun.ptr << "]\n";
qmu::console() << "CALL STRFUNC\t";
qmu::console() << "[ARG:" << std::dec << m_vRPN[i].Fun.argc << "]";
qmu::console() << "[IDX:" << std::dec << m_vRPN[i].Fun.idx << "]";
qmu::console() << "[ADDR: 0x" << m_vRPN[i].Fun.ptr << "]\n";
break;
case cmLT: mu::console() << "LT\n"; break;
case cmGT: mu::console() << "GT\n"; break;
case cmLE: mu::console() << "LE\n"; break;
case cmGE: mu::console() << "GE\n"; break;
case cmEQ: mu::console() << "EQ\n"; break;
case cmNEQ: mu::console() << "NEQ\n"; break;
case cmADD: mu::console() << "ADD\n"; break;
case cmLAND: mu::console() << "&&\n"; break;
case cmLOR: mu::console() << "||\n"; break;
case cmSUB: mu::console() << "SUB\n"; break;
case cmMUL: mu::console() << "MUL\n"; break;
case cmDIV: mu::console() << "DIV\n"; break;
case cmPOW: mu::console() << "POW\n"; break;
case cmLT: qmu::console() << "LT\n"; break;
case cmGT: qmu::console() << "GT\n"; break;
case cmLE: qmu::console() << "LE\n"; break;
case cmGE: qmu::console() << "GE\n"; break;
case cmEQ: qmu::console() << "EQ\n"; break;
case cmNEQ: qmu::console() << "NEQ\n"; break;
case cmADD: qmu::console() << "ADD\n"; break;
case cmLAND: qmu::console() << "&&\n"; break;
case cmLOR: qmu::console() << "||\n"; break;
case cmSUB: qmu::console() << "SUB\n"; break;
case cmMUL: qmu::console() << "MUL\n"; break;
case cmDIV: qmu::console() << "DIV\n"; break;
case cmPOW: qmu::console() << "POW\n"; break;
case cmIF: mu::console() << "IF\t";
mu::console() << "[OFFSET:" << std::dec << m_vRPN[i].Oprt.offset << "]\n";
case cmIF: qmu::console() << "IF\t";
qmu::console() << "[OFFSET:" << std::dec << m_vRPN[i].Oprt.offset << "]\n";
break;
case cmELSE: mu::console() << "ELSE\t";
mu::console() << "[OFFSET:" << std::dec << m_vRPN[i].Oprt.offset << "]\n";
case cmELSE: qmu::console() << "ELSE\t";
qmu::console() << "[OFFSET:" << std::dec << m_vRPN[i].Oprt.offset << "]\n";
break;
case cmENDIF: mu::console() << "ENDIF\n"; break;
case cmENDIF: qmu::console() << "ENDIF\n"; break;
case cmASSIGN:
mu::console() << "ASSIGN\t";
mu::console() << "[ADDR: 0x" << m_vRPN[i].Oprt.ptr << "]\n";
qmu::console() << "ASSIGN\t";
qmu::console() << "[ADDR: 0x" << m_vRPN[i].Oprt.ptr << "]\n";
break;
default: mu::console() << "(unknown code: " << m_vRPN[i].Cmd << ")\n";
default: qmu::console() << "(unknown code: " << m_vRPN[i].Cmd << ")\n";
break;
} // switch cmdCode
} // while bytecode
mu::console() << "END" << std::endl;
qmu::console() << "END" << std::endl;
}
} // namespace qmu

View file

@ -1,150 +0,0 @@
#ifndef QMUPARSERTEMPLATEMAGIC_H
#define QMUPARSERTEMPLATEMAGIC_H
#include <cmath>
#include "muParserError.h"
namespace qmu
{
//-----------------------------------------------------------------------------------------------
//
// Compile time type detection
//
//-----------------------------------------------------------------------------------------------
/** \brief A class singling out integer types at compile time using
template meta programming.
*/
template<typename T>
struct TypeInfo
{
static bool IsInteger() { return false; }
};
template<>
struct TypeInfo<char>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<short>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<int>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<long>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<unsigned char>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<unsigned short>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<unsigned int>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<unsigned long>
{
static bool IsInteger() { return true; }
};
//-----------------------------------------------------------------------------------------------
//
// Standard math functions with dummy overload for integer types
//
//-----------------------------------------------------------------------------------------------
/** \brief A template class for providing wrappers for essential math functions.
This template is spezialized for several types in order to provide a unified interface
for parser internal math function calls regardless of the data type.
*/
template<typename T>
struct MathImpl
{
static T Sin(T v) { return sin(v); }
static T Cos(T v) { return cos(v); }
static T Tan(T v) { return tan(v); }
static T ASin(T v) { return asin(v); }
static T ACos(T v) { return acos(v); }
static T ATan(T v) { return atan(v); }
static T ATan2(T v1, T v2) { return atan2(v1, v2); }
static T Sinh(T v) { return sinh(v); }
static T Cosh(T v) { return cosh(v); }
static T Tanh(T v) { return tanh(v); }
static T ASinh(T v) { return log(v + sqrt(v * v + 1)); }
static T ACosh(T v) { return log(v + sqrt(v * v - 1)); }
static T ATanh(T v) { return ((T)0.5 * log((1 + v) / (1 - v))); }
static T Log(T v) { return log(v); }
static T Log2(T v) { return log(v)/log((T)2); } // Logarithm base 2
static T Log10(T v) { return log10(v); } // Logarithm base 10
static T Exp(T v) { return exp(v); }
static T Abs(T v) { return (v>=0) ? v : -v; }
static T Sqrt(T v) { return sqrt(v); }
static T Rint(T v) { return floor(v + (T)0.5); }
static T Sign(T v) { return (T)((v<0) ? -1 : (v>0) ? 1 : 0); }
static T Pow(T v1, T v2) { return std::pow(v1, v2); }
};
// Create (mostly) dummy math function definitions for integer types. They are mostly
// empty since they are not applicable for integer values.
#define MAKE_MATH_DUMMY(TYPE) \
template<> \
struct MathImpl<TYPE> \
{ \
static TYPE Sin(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Cos(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Tan(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE ASin(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE ACos(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE ATan(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE ATan2(TYPE, TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Sinh(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Cosh(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Tanh(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE ASinh(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE ACosh(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE ATanh(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Log(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Log2(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Log10(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Exp(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Abs(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Sqrt(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Rint(TYPE) { throw QmuParserError("unimplemented function."); } \
static TYPE Sign(TYPE v) { return (TYPE)((v<0) ? -1 : (v>0) ? 1 : 0); } \
static TYPE Pow(TYPE v1, TYPE v2) { return (TYPE)std::pow((double)v1, (double)v2); } \
};
MAKE_MATH_DUMMY(char)
MAKE_MATH_DUMMY(short)
MAKE_MATH_DUMMY(int)
MAKE_MATH_DUMMY(long)
#undef MAKE_MATH_DUMMY
}
#endif

View file

@ -88,7 +88,7 @@ namespace qmu
int QmuParserTester::TestInterface()
{
int iStat = 0;
mu::console() << "testing member functions...";
qmu::console() << "testing member functions...";
// Test RemoveVar
qreal afVal[3] = {1,2,3};
@ -119,9 +119,9 @@ namespace qmu
}
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -130,7 +130,7 @@ namespace qmu
int QmuParserTester::TestStrArg()
{
int iStat = 0;
mu::console() << "testing string arguments...";
qmu::console() << "testing string arguments...";
iStat += EqnTest("valueof(\"\")", 123, true); // empty string arguments caused a crash
iStat += EqnTest("valueof(\"aaa\")+valueof(\"bbb\") ", 246, true);
@ -144,9 +144,9 @@ namespace qmu
iStat += EqnTest("strfun3(\"99\",1,2)", 102, true);
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -155,7 +155,7 @@ namespace qmu
int QmuParserTester::TestBinOprt()
{
int iStat = 0;
mu::console() << "testing binary operators...";
qmu::console() << "testing binary operators...";
// built in operators
// xor operator
@ -288,9 +288,9 @@ namespace qmu
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -302,7 +302,7 @@ namespace qmu
int iStat= 0,
iErr = 0;
mu::console() << "testing name restriction enforcement...";
qmu::console() << "testing name restriction enforcement...";
QmuParser p;
@ -397,9 +397,9 @@ namespace qmu
#undef PARSER_THROWCHECK
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -408,7 +408,7 @@ namespace qmu
int QmuParserTester::TestSyntax()
{
int iStat = 0;
mu::console() << "testing syntax engine...";
qmu::console() << "testing syntax engine...";
iStat += ThrowTest("1,", ecUNEXPECTED_EOF); // incomplete hex definition
iStat += ThrowTest("a,", ecUNEXPECTED_EOF); // incomplete hex definition
@ -446,9 +446,9 @@ namespace qmu
iStat += EqnTest("sin()", 0, false); // unexpected closing bracket
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -457,7 +457,7 @@ namespace qmu
int QmuParserTester::TestVarConst()
{
int iStat = 0;
mu::console() << "testing variable/constant detection...";
qmu::console() << "testing variable/constant detection...";
// Test if the result changes when a variable changes
iStat += EqnTestWithVarChange( "a", 1, 1, 2, 2 );
@ -504,7 +504,7 @@ namespace qmu
// Test lookup of defined variables
// 4 used variables
p.SetExpr( "a+b+c+d" );
mu::varmap_type UsedVar = p.GetUsedVar();
qmu::varmap_type UsedVar = p.GetUsedVar();
int iCount = (int)UsedVar.size();
if (iCount!=4)
throw false;
@ -514,7 +514,7 @@ namespace qmu
if (p.GetVar().size()!=5)
throw false;
mu::varmap_type::const_iterator item = UsedVar.begin();
qmu::varmap_type::const_iterator item = UsedVar.begin();
for (idx=0; item!=UsedVar.end(); ++item)
{
if (&vVarVal[idx++]!=item->second)
@ -555,9 +555,9 @@ namespace qmu
}
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -566,7 +566,7 @@ namespace qmu
int QmuParserTester::TestMultiArg()
{
int iStat = 0;
mu::console() << "testing multiarg functions...";
qmu::console() << "testing multiarg functions...";
// Compound expressions
iStat += EqnTest( "1,2,3", 3, true);
@ -649,9 +649,9 @@ namespace qmu
iStat += EqnTest( "sum(,1,2)", 0, false);
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -661,7 +661,7 @@ namespace qmu
int QmuParserTester::TestInfixOprt()
{
int iStat(0);
mu::console() << "testing infix operators...";
qmu::console() << "testing infix operators...";
iStat += EqnTest( "-1", -1, true);
iStat += EqnTest( "-(-1)", 1, true);
@ -714,9 +714,9 @@ namespace qmu
iStat += EqnTest( "~~ 123", 123+2, true);
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -726,7 +726,7 @@ namespace qmu
int QmuParserTester::TestPostFix()
{
int iStat = 0;
mu::console() << "testing postfix operators...";
qmu::console() << "testing postfix operators...";
// application
iStat += EqnTest( "3{m}+5", 5.003, true);
@ -766,9 +766,9 @@ namespace qmu
iStat += ThrowTest( "multi*1.0", ecUNASSIGNABLE_TOKEN);
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -777,7 +777,7 @@ namespace qmu
int QmuParserTester::TestExpression()
{
int iStat = 0;
mu::console() << "testing expression samples...";
qmu::console() << "testing expression samples...";
qreal b = 2;
@ -846,9 +846,9 @@ namespace qmu
iStat += EqnTest( "1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12", -7995810.09926, true);
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -859,7 +859,7 @@ namespace qmu
int QmuParserTester::TestIfThenElse()
{
int iStat = 0;
mu::console() << "testing if-then-else operator...";
qmu::console() << "testing if-then-else operator...";
// Test error detection
iStat += ThrowTest(":3", ecUNEXPECTED_CONDITIONAL);
@ -954,9 +954,9 @@ namespace qmu
iStat += EqnTest("a=0?5:b=1?3:4, b", 3, true);
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -965,7 +965,7 @@ namespace qmu
int QmuParserTester::TestException()
{
int iStat = 0;
mu::console() << "testing error codes...";
qmu::console() << "testing error codes...";
iStat += ThrowTest("3+", ecUNEXPECTED_EOF);
iStat += ThrowTest("3+)", ecUNEXPECTED_PARENS);
@ -1048,9 +1048,9 @@ namespace qmu
iStat += ThrowTest( "a=\"tttt\"", ecOPRT_TYPE_CONFLICT);
if (iStat==0)
mu::console() << "passed" << endl;
qmu::console() << "passed" << endl;
else
mu::console() << "\n failed with " << iStat << " errors" << endl;
qmu::console() << "\n failed with " << iStat << " errors" << endl;
return iStat;
}
@ -1073,28 +1073,28 @@ namespace qmu
}
catch(QmuParser::exception_type &e)
{
mu::console() << "\n" << e.GetMsg() << endl;
mu::console() << e.GetToken() << endl;
qmu::console() << "\n" << e.GetMsg() << endl;
qmu::console() << e.GetToken() << endl;
Abort();
}
catch(std::exception &e)
{
mu::console() << e.what() << endl;
qmu::console() << e.what() << endl;
Abort();
}
catch(...)
{
mu::console() << "Internal error";
qmu::console() << "Internal error";
Abort();
}
if (iStat==0)
{
mu::console() << "Test passed (" << QmuParserTester::c_iCount << " expressions)" << endl;
qmu::console() << "Test passed (" << QmuParserTester::c_iCount << " expressions)" << endl;
}
else
{
mu::console() << "Test failed with " << iStat
qmu::console() << "Test failed with " << iStat
<< " errors (" << QmuParserTester::c_iCount
<< " expressions)" << endl;
}
@ -1130,7 +1130,7 @@ namespace qmu
// output the formula in case of an failed test
if (a_bFail==false || (a_bFail==true && a_iErrc!=e.GetCode()) )
{
mu::console() << "\n "
qmu::console() << "\n "
<< "Expression: " << a_str
<< " Code:" << e.GetCode() << "(" << e.GetMsg() << ")"
<< " Expected:" << a_iErrc;
@ -1143,7 +1143,7 @@ namespace qmu
bool bRet((a_bFail==false) ? 0 : 1);
if (bRet==1)
{
mu::console() << "\n "
qmu::console() << "\n "
<< "Expression: " << a_str
<< " did evaluate; Expected error:" << a_iErrc;
}
@ -1188,17 +1188,17 @@ namespace qmu
}
catch(QmuParser::exception_type &e)
{
mu::console() << "\n fail: " << a_str.c_str() << " (" << e.GetMsg() << ")";
qmu::console() << "\n fail: " << a_str.c_str() << " (" << e.GetMsg() << ")";
return 1;
}
catch(std::exception &e)
{
mu::console() << "\n fail: " << a_str.c_str() << " (" << e.what() << ")";
qmu::console() << "\n fail: " << a_str.c_str() << " (" << e.what() << ")";
return 1; // always return a failure since this exception is not expected
}
catch(...)
{
mu::console() << "\n fail: " << a_str.c_str() << " (unexpected exception)";
qmu::console() << "\n fail: " << a_str.c_str() << " (unexpected exception)";
return 1; // exceptions other than ParserException are not allowed
}
@ -1329,7 +1329,7 @@ namespace qmu
}
catch(std::exception &e)
{
mu::console() << "\n " << e.what() << "\n";
qmu::console() << "\n " << e.what() << "\n";
}
// limited floating point accuracy requires the following test
@ -1350,7 +1350,7 @@ namespace qmu
if (iRet==1)
{
mu::console() << "\n fail: " << a_str.c_str()
qmu::console() << "\n fail: " << a_str.c_str()
<< " (incorrect result; expected: " << a_fRes
<< " ;calculated: " << fVal[0] << ","
<< fVal[1] << ","
@ -1364,20 +1364,20 @@ namespace qmu
if (a_fPass)
{
if (fVal[0]!=fVal[2] && fVal[0]!=-999 && fVal[1]!=-998)
mu::console() << "\n fail: " << a_str.c_str() << " (copy construction)";
qmu::console() << "\n fail: " << a_str.c_str() << " (copy construction)";
else
mu::console() << "\n fail: " << a_str.c_str() << " (" << e.GetMsg() << ")";
qmu::console() << "\n fail: " << a_str.c_str() << " (" << e.GetMsg() << ")";
return 1;
}
}
catch(std::exception &e)
{
mu::console() << "\n fail: " << a_str.c_str() << " (" << e.what() << ")";
qmu::console() << "\n fail: " << a_str.c_str() << " (" << e.what() << ")";
return 1; // always return a failure since this exception is not expected
}
catch(...)
{
mu::console() << "\n fail: " << a_str.c_str() << " (unexpected exception)";
qmu::console() << "\n fail: " << a_str.c_str() << " (unexpected exception)";
return 1; // exceptions other than ParserException are not allowed
}
@ -1413,7 +1413,7 @@ namespace qmu
(a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1;
if (iRet==1)
{
mu::console() << "\n fail: " << a_str.c_str()
qmu::console() << "\n fail: " << a_str.c_str()
<< " (incorrect result; expected: " << a_fRes
<< " ;calculated: " << fVal[0]<< ").";
}
@ -1422,13 +1422,13 @@ namespace qmu
{
if (a_fPass)
{
mu::console() << "\n fail: " << e.GetExpr() << " : " << e.GetMsg();
qmu::console() << "\n fail: " << e.GetExpr() << " : " << e.GetMsg();
iRet = 1;
}
}
catch(...)
{
mu::console() << "\n fail: " << a_str.c_str() << " (unexpected exception)";
qmu::console() << "\n fail: " << a_str.c_str() << " (unexpected exception)";
iRet = 1; // exceptions other than ParserException are not allowed
}
@ -1439,7 +1439,7 @@ namespace qmu
/** \brief Internal error in test class Test is going to be aborted. */
void QmuParserTester::Abort() const
{
mu::console() << "Test failed (internal error in test class)" << endl;
qmu::console() << "Test failed (internal error in test class)" << endl;
while (!getchar());
exit(-1);
}

View file

@ -28,6 +28,7 @@
#include <stack>
#include <vector>
#include <memory>
#include <QtGlobal>
#include "qmuparsererror.h"
#include "qmuparsercallback.h"