Successful build after adding muParser library.
--HG-- branch : feature
This commit is contained in:
parent
1e99fb68c1
commit
0b4d69f821
|
@ -232,3 +232,9 @@ for(DIR, INSTALL_INDIVIDUAL_MEASHUREMENTS) {
|
||||||
|
|
||||||
copyToDestdir($$ind_path, $$shell_path($$OUT_PWD/$$DESTDIR/tables/individual))
|
copyToDestdir($$ind_path, $$shell_path($$OUT_PWD/$$DESTDIR/tables/individual))
|
||||||
|
|
||||||
|
win32:CONFIG(release, debug|release): LIBS += -L../libs/qmuparser/bin -lqmuparser
|
||||||
|
else:win32:CONFIG(debug, debug|release): LIBS += -L../libs/qmuparser/bin -lqmuparser
|
||||||
|
else:unix: LIBS += -L../libs/qmuparser/bin -lqmuparser
|
||||||
|
|
||||||
|
INCLUDEPATH += ../libs/qmuparser
|
||||||
|
DEPENDPATH += ../libs/qmuparser
|
||||||
|
|
|
@ -29,10 +29,8 @@
|
||||||
#ifndef STABLE_H
|
#ifndef STABLE_H
|
||||||
#define STABLE_H
|
#define STABLE_H
|
||||||
|
|
||||||
/* I like to include this pragma too,
|
/* I like to include this pragma too, so the build log indicates if pre-compiled headers were in use. */
|
||||||
so the build log indicates if pre-compiled headers
|
#pragma message("Compiling precompiled headers for Valentina.\n")
|
||||||
were in use. */
|
|
||||||
#pragma message("Compiling precompiled headers.\n")
|
|
||||||
|
|
||||||
/* Add C includes here */
|
/* Add C includes here */
|
||||||
|
|
||||||
|
|
29
src/libs/qmuparser/License.txt
Normal file
29
src/libs/qmuparser/License.txt
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#######################################################################
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
# Fast math parser Library #
|
||||||
|
# #
|
||||||
|
# Copyright (C) 2011 Ingo Berg #
|
||||||
|
# #
|
||||||
|
# Web: muparser.beltoforion.de #
|
||||||
|
# e-mail: muparser@beltoforion.de #
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
OR OTHER DEALINGS IN THE SOFTWARE.
|
1563
src/libs/qmuparser/doc/Doxyfile
Normal file
1563
src/libs/qmuparser/doc/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
383
src/libs/qmuparser/qmuparser.cpp
Normal file
383
src/libs/qmuparser/qmuparser.cpp
Normal file
|
@ -0,0 +1,383 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "qmuparser.h"
|
||||||
|
#include "qmuparsertemplatemagic.h"
|
||||||
|
|
||||||
|
//--- Standard includes ------------------------------------------------------------------------
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
/** \brief Pi (what else?). */
|
||||||
|
#define QmuParser_CONST_PI 3.141592653589793238462643
|
||||||
|
|
||||||
|
/** \brief The eulerian number. */
|
||||||
|
#define QmuParser_CONST_E 2.718281828459045235360287
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief Implementation of the standard floating point QmuParser.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Namespace for mathematical applications. */
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Trigonometric function
|
||||||
|
value_type QmuParser::Sin(value_type v) { return MathImpl<value_type>::Sin(v); }
|
||||||
|
value_type QmuParser::Cos(value_type v) { return MathImpl<value_type>::Cos(v); }
|
||||||
|
value_type QmuParser::Tan(value_type v) { return MathImpl<value_type>::Tan(v); }
|
||||||
|
value_type QmuParser::ASin(value_type v) { return MathImpl<value_type>::ASin(v); }
|
||||||
|
value_type QmuParser::ACos(value_type v) { return MathImpl<value_type>::ACos(v); }
|
||||||
|
value_type QmuParser::ATan(value_type v) { return MathImpl<value_type>::ATan(v); }
|
||||||
|
value_type QmuParser::ATan2(value_type v1, value_type v2) { return MathImpl<value_type>::ATan2(v1, v2); }
|
||||||
|
value_type QmuParser::Sinh(value_type v) { return MathImpl<value_type>::Sinh(v); }
|
||||||
|
value_type QmuParser::Cosh(value_type v) { return MathImpl<value_type>::Cosh(v); }
|
||||||
|
value_type QmuParser::Tanh(value_type v) { return MathImpl<value_type>::Tanh(v); }
|
||||||
|
value_type QmuParser::ASinh(value_type v) { return MathImpl<value_type>::ASinh(v); }
|
||||||
|
value_type QmuParser::ACosh(value_type v) { return MathImpl<value_type>::ACosh(v); }
|
||||||
|
value_type QmuParser::ATanh(value_type v) { return MathImpl<value_type>::ATanh(v); }
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Logarithm functions
|
||||||
|
|
||||||
|
// Logarithm base 2
|
||||||
|
value_type QmuParser::Log2(value_type v)
|
||||||
|
{
|
||||||
|
#ifdef MUP_MATH_EXCEPTIONS
|
||||||
|
if (v<=0)
|
||||||
|
throw QmuParserError(ecDOMAIN_ERROR, _T("Log2"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return MathImpl<value_type>::Log2(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logarithm base 10
|
||||||
|
value_type QmuParser::Log10(value_type v)
|
||||||
|
{
|
||||||
|
#ifdef MUP_MATH_EXCEPTIONS
|
||||||
|
if (v<=0)
|
||||||
|
throw QmuParserError(ecDOMAIN_ERROR, _T("Log10"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return MathImpl<value_type>::Log10(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logarithm base e (natural logarithm)
|
||||||
|
value_type QmuParser::Ln(value_type v)
|
||||||
|
{
|
||||||
|
#ifdef MUP_MATH_EXCEPTIONS
|
||||||
|
if (v<=0)
|
||||||
|
throw QmuParserError(ecDOMAIN_ERROR, _T("Ln"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return MathImpl<value_type>::Log(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// misc
|
||||||
|
value_type QmuParser::Exp(value_type v) { return MathImpl<value_type>::Exp(v); }
|
||||||
|
value_type QmuParser::Abs(value_type v) { return MathImpl<value_type>::Abs(v); }
|
||||||
|
value_type QmuParser::Sqrt(value_type v)
|
||||||
|
{
|
||||||
|
#ifdef MUP_MATH_EXCEPTIONS
|
||||||
|
if (v<0)
|
||||||
|
throw QmuParserError(ecDOMAIN_ERROR, _T("sqrt"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return MathImpl<value_type>::Sqrt(v);
|
||||||
|
}
|
||||||
|
value_type QmuParser::Rint(value_type v) { return MathImpl<value_type>::Rint(v); }
|
||||||
|
value_type QmuParser::Sign(value_type v) { return MathImpl<value_type>::Sign(v); }
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Callback for the unary minus operator.
|
||||||
|
\param v The value to negate
|
||||||
|
\return -v
|
||||||
|
*/
|
||||||
|
value_type QmuParser::UnaryMinus(value_type v)
|
||||||
|
{
|
||||||
|
return -v;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Callback for adding multiple values.
|
||||||
|
\param [in] a_afArg Vector with the function arguments
|
||||||
|
\param [in] a_iArgc The size of a_afArg
|
||||||
|
*/
|
||||||
|
value_type QmuParser::Sum(const value_type *a_afArg, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (!a_iArgc)
|
||||||
|
throw exception_type(_T("too few arguments for function sum."));
|
||||||
|
|
||||||
|
value_type fRes=0;
|
||||||
|
for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];
|
||||||
|
return fRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Callback for averaging multiple values.
|
||||||
|
\param [in] a_afArg Vector with the function arguments
|
||||||
|
\param [in] a_iArgc The size of a_afArg
|
||||||
|
*/
|
||||||
|
value_type QmuParser::Avg(const value_type *a_afArg, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (!a_iArgc)
|
||||||
|
throw exception_type(_T("too few arguments for function sum."));
|
||||||
|
|
||||||
|
value_type fRes=0;
|
||||||
|
for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];
|
||||||
|
return fRes/(value_type)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
|
||||||
|
*/
|
||||||
|
value_type QmuParser::Min(const value_type *a_afArg, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (!a_iArgc)
|
||||||
|
throw exception_type(_T("too few arguments for function min."));
|
||||||
|
|
||||||
|
value_type fRes=a_afArg[0];
|
||||||
|
for (int i=0; i<a_iArgc; ++i)
|
||||||
|
fRes = std::min(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
|
||||||
|
*/
|
||||||
|
value_type QmuParser::Max(const value_type *a_afArg, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (!a_iArgc)
|
||||||
|
throw exception_type(_T("too few arguments for function min."));
|
||||||
|
|
||||||
|
value_type fRes=a_afArg[0];
|
||||||
|
for (int i=0; i<a_iArgc; ++i) fRes = std::max(fRes, a_afArg[i]);
|
||||||
|
|
||||||
|
return fRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Default value recognition callback.
|
||||||
|
\param [in] a_szExpr Pointer to the expression
|
||||||
|
\param [in, out] a_iPos Pointer to an index storing the current position within the expression
|
||||||
|
\param [out] a_fVal Pointer where the value should be stored in case one is found.
|
||||||
|
\return 1 if a value was found 0 otherwise.
|
||||||
|
*/
|
||||||
|
int QmuParser::IsVal(const char_type* a_szExpr, int *a_iPos, value_type *a_fVal)
|
||||||
|
{
|
||||||
|
value_type fVal(0);
|
||||||
|
|
||||||
|
stringstream_type stream(a_szExpr);
|
||||||
|
stream.seekg(0); // todo: check if this really is necessary
|
||||||
|
stream.imbue(QmuParser::s_locale);
|
||||||
|
stream >> fVal;
|
||||||
|
stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading
|
||||||
|
|
||||||
|
if (iEnd==(stringstream_type::pos_type)-1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*a_iPos += (int)iEnd;
|
||||||
|
*a_fVal = fVal;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Constructor.
|
||||||
|
|
||||||
|
Call QmuParserBase class constructor and trigger Function, Operator and Constant initialization.
|
||||||
|
*/
|
||||||
|
QmuParser::QmuParser()
|
||||||
|
:QmuParserBase()
|
||||||
|
{
|
||||||
|
AddValIdent(IsVal);
|
||||||
|
|
||||||
|
InitCharSets();
|
||||||
|
InitFun();
|
||||||
|
InitConst();
|
||||||
|
InitOprt();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Define the character sets.
|
||||||
|
\sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars
|
||||||
|
|
||||||
|
This function is used for initializing the default character sets that define
|
||||||
|
the characters to be useable in function and variable names and operators.
|
||||||
|
*/
|
||||||
|
void QmuParser::InitCharSets()
|
||||||
|
{
|
||||||
|
DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") );
|
||||||
|
DefineOprtChars( _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}") );
|
||||||
|
DefineInfixOprtChars( _T("/+-*^?<>=#!$%&|~'_") );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Initialize the default functions. */
|
||||||
|
void QmuParser::InitFun()
|
||||||
|
{
|
||||||
|
if (qmu::TypeInfo<qmu::value_type>::IsInteger())
|
||||||
|
{
|
||||||
|
// When setting MUP_BASETYPE to an integer type
|
||||||
|
// Place functions for dealing with integer values here
|
||||||
|
// ...
|
||||||
|
// ...
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// trigonometric functions
|
||||||
|
DefineFun(_T("sin"), Sin);
|
||||||
|
DefineFun(_T("cos"), Cos);
|
||||||
|
DefineFun(_T("tan"), Tan);
|
||||||
|
// arcus functions
|
||||||
|
DefineFun(_T("asin"), ASin);
|
||||||
|
DefineFun(_T("acos"), ACos);
|
||||||
|
DefineFun(_T("atan"), ATan);
|
||||||
|
DefineFun(_T("atan2"), ATan2);
|
||||||
|
// hyperbolic functions
|
||||||
|
DefineFun(_T("sinh"), Sinh);
|
||||||
|
DefineFun(_T("cosh"), Cosh);
|
||||||
|
DefineFun(_T("tanh"), Tanh);
|
||||||
|
// arcus hyperbolic functions
|
||||||
|
DefineFun(_T("asinh"), ASinh);
|
||||||
|
DefineFun(_T("acosh"), ACosh);
|
||||||
|
DefineFun(_T("atanh"), ATanh);
|
||||||
|
// Logarithm functions
|
||||||
|
DefineFun(_T("log2"), Log2);
|
||||||
|
DefineFun(_T("log10"), Log10);
|
||||||
|
DefineFun(_T("log"), Log10);
|
||||||
|
DefineFun(_T("ln"), Ln);
|
||||||
|
// misc
|
||||||
|
DefineFun(_T("exp"), Exp);
|
||||||
|
DefineFun(_T("sqrt"), Sqrt);
|
||||||
|
DefineFun(_T("sign"), Sign);
|
||||||
|
DefineFun(_T("rint"), Rint);
|
||||||
|
DefineFun(_T("abs"), Abs);
|
||||||
|
// Functions with variable number of arguments
|
||||||
|
DefineFun(_T("sum"), Sum);
|
||||||
|
DefineFun(_T("avg"), Avg);
|
||||||
|
DefineFun(_T("min"), Min);
|
||||||
|
DefineFun(_T("max"), Max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Initialize constants.
|
||||||
|
|
||||||
|
By default the QmuParser recognizes two constants. Pi ("pi") and the eulerian
|
||||||
|
number ("_e").
|
||||||
|
*/
|
||||||
|
void QmuParser::InitConst()
|
||||||
|
{
|
||||||
|
DefineConst(_T("_pi"), (value_type)QmuParser_CONST_PI);
|
||||||
|
DefineConst(_T("_e"), (value_type)QmuParser_CONST_E);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Initialize operators.
|
||||||
|
|
||||||
|
By default only the unary minus operator is added.
|
||||||
|
*/
|
||||||
|
void QmuParser::InitOprt()
|
||||||
|
{
|
||||||
|
DefineInfixOprt(_T("-"), UnaryMinus);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void QmuParser::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/)
|
||||||
|
{
|
||||||
|
// this is just sample code to illustrate modifying variable names on the fly.
|
||||||
|
// I'm not sure anyone really needs such a feature...
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
string sVar(pExpr->begin()+nStart, pExpr->begin()+nEnd);
|
||||||
|
string sRepl = std::string("_") + sVar + "_";
|
||||||
|
|
||||||
|
int nOrigVarEnd = nEnd;
|
||||||
|
cout << "variable detected!\n";
|
||||||
|
cout << " Expr: " << *pExpr << "\n";
|
||||||
|
cout << " Start: " << nStart << "\n";
|
||||||
|
cout << " End: " << nEnd << "\n";
|
||||||
|
cout << " Var: \"" << sVar << "\"\n";
|
||||||
|
cout << " Repl: \"" << sRepl << "\"\n";
|
||||||
|
nEnd = nStart + sRepl.length();
|
||||||
|
cout << " End: " << nEnd << "\n";
|
||||||
|
pExpr->replace(pExpr->begin()+nStart, pExpr->begin()+nOrigVarEnd, sRepl);
|
||||||
|
cout << " New expr: " << *pExpr << "\n";
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Numerically differentiate with regard to a variable.
|
||||||
|
\param [in] a_Var Pointer to the differentiation variable.
|
||||||
|
\param [in] a_fPos Position at which the differentiation should take place.
|
||||||
|
\param [in] a_fEpsilon Epsilon used for the numerical differentiation.
|
||||||
|
|
||||||
|
Numerical differentiation uses a 5 point operator yielding a 4th order
|
||||||
|
formula. The default value for epsilon is 0.00074 which is
|
||||||
|
numeric_limits<double>::epsilon() ^ (1/5) as suggested in the muQmuParser
|
||||||
|
forum:
|
||||||
|
|
||||||
|
http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843
|
||||||
|
*/
|
||||||
|
value_type QmuParser::Diff(value_type *a_Var,
|
||||||
|
value_type a_fPos,
|
||||||
|
value_type a_fEpsilon) const
|
||||||
|
{
|
||||||
|
value_type fRes(0),
|
||||||
|
fBuf(*a_Var),
|
||||||
|
f[4] = {0,0,0,0},
|
||||||
|
fEpsilon(a_fEpsilon);
|
||||||
|
|
||||||
|
// Backwards compatible calculation of epsilon inc case the user doesnt provide
|
||||||
|
// his own epsilon
|
||||||
|
if (fEpsilon==0)
|
||||||
|
fEpsilon = (a_fPos==0) ? (value_type)1e-10 : (value_type)1e-7 * a_fPos;
|
||||||
|
|
||||||
|
*a_Var = a_fPos+2 * fEpsilon; f[0] = Eval();
|
||||||
|
*a_Var = a_fPos+1 * fEpsilon; f[1] = Eval();
|
||||||
|
*a_Var = a_fPos-1 * fEpsilon; f[2] = Eval();
|
||||||
|
*a_Var = a_fPos-2 * fEpsilon; f[3] = Eval();
|
||||||
|
*a_Var = fBuf; // restore variable
|
||||||
|
|
||||||
|
fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon);
|
||||||
|
return fRes;
|
||||||
|
}
|
||||||
|
} // namespace qmu
|
110
src/libs/qmuparser/qmuparser.h
Normal file
110
src/libs/qmuparser/qmuparser.h
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPARSER_H
|
||||||
|
#define QMUPARSER_H
|
||||||
|
|
||||||
|
#include "qmuparser_global.h"
|
||||||
|
|
||||||
|
//--- Standard includes ------------------------------------------------------------------------
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//--- Parser includes --------------------------------------------------------------------------
|
||||||
|
#include "qmuparserbase.h"
|
||||||
|
#include "qmuparsertemplatemagic.h"
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief Definition of the standard floating point parser.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
/** \brief Mathematical expressions parser.
|
||||||
|
|
||||||
|
Standard implementation of the mathematical expressions parser.
|
||||||
|
Can be used as a reference implementation for subclassing the parser.
|
||||||
|
|
||||||
|
<small>
|
||||||
|
(C) 2011 Ingo Berg<br>
|
||||||
|
muparser(at)gmx.de
|
||||||
|
</small>
|
||||||
|
*/
|
||||||
|
/* final */ class QMUPARSERSHARED_EXPORT QmuParser : public QmuParserBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
QmuParser();
|
||||||
|
virtual void InitCharSets();
|
||||||
|
virtual void InitFun();
|
||||||
|
virtual void InitConst();
|
||||||
|
virtual void InitOprt();
|
||||||
|
virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd);
|
||||||
|
|
||||||
|
value_type Diff(value_type *a_Var, value_type a_fPos, value_type a_fEpsilon = 0) const;
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// Trigonometric functions
|
||||||
|
static value_type Sin(value_type);
|
||||||
|
static value_type Cos(value_type);
|
||||||
|
static value_type Tan(value_type);
|
||||||
|
static value_type Tan2(value_type, value_type);
|
||||||
|
// arcus functions
|
||||||
|
static value_type ASin(value_type);
|
||||||
|
static value_type ACos(value_type);
|
||||||
|
static value_type ATan(value_type);
|
||||||
|
static value_type ATan2(value_type, value_type);
|
||||||
|
|
||||||
|
// hyperbolic functions
|
||||||
|
static value_type Sinh(value_type);
|
||||||
|
static value_type Cosh(value_type);
|
||||||
|
static value_type Tanh(value_type);
|
||||||
|
// arcus hyperbolic functions
|
||||||
|
static value_type ASinh(value_type);
|
||||||
|
static value_type ACosh(value_type);
|
||||||
|
static value_type ATanh(value_type);
|
||||||
|
// Logarithm functions
|
||||||
|
static value_type Log2(value_type); // Logarithm Base 2
|
||||||
|
static value_type Log10(value_type); // Logarithm Base 10
|
||||||
|
static value_type Ln(value_type); // Logarithm Base e (natural logarithm)
|
||||||
|
// misc
|
||||||
|
static value_type Exp(value_type);
|
||||||
|
static value_type Abs(value_type);
|
||||||
|
static value_type Sqrt(value_type);
|
||||||
|
static value_type Rint(value_type);
|
||||||
|
static value_type Sign(value_type);
|
||||||
|
|
||||||
|
// Prefix operators
|
||||||
|
// !!! Unary Minus is a MUST if you want to use negative signs !!!
|
||||||
|
static value_type UnaryMinus(value_type);
|
||||||
|
|
||||||
|
// Functions with variable number of arguments
|
||||||
|
static value_type Sum(const value_type*, int); // sum
|
||||||
|
static value_type Avg(const value_type*, int); // mean value
|
||||||
|
static value_type Min(const value_type*, int); // minimum
|
||||||
|
static value_type Max(const value_type*, int); // maximum
|
||||||
|
|
||||||
|
static int IsVal(const char_type* a_szExpr, int *a_iPos, value_type *a_fVal);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qmu
|
||||||
|
|
||||||
|
#endif // QMUPARSER_H
|
112
src/libs/qmuparser/qmuparser.pro
Normal file
112
src/libs/qmuparser/qmuparser.pro
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#-------------------------------------------------
|
||||||
|
#
|
||||||
|
# Project created by QtCreator 2014-04-25T12:01:49
|
||||||
|
#
|
||||||
|
#-------------------------------------------------
|
||||||
|
|
||||||
|
QT -= gui
|
||||||
|
|
||||||
|
TARGET = qmuparser
|
||||||
|
TEMPLATE = lib
|
||||||
|
|
||||||
|
CONFIG -= debug_and_release debug_and_release_target
|
||||||
|
CONFIG += c++11
|
||||||
|
|
||||||
|
DEFINES += QMUPARSER_LIBRARY
|
||||||
|
|
||||||
|
# directory for executable file
|
||||||
|
DESTDIR = bin
|
||||||
|
|
||||||
|
# files created moc
|
||||||
|
MOC_DIR = moc
|
||||||
|
|
||||||
|
# objecs files
|
||||||
|
OBJECTS_DIR = obj
|
||||||
|
|
||||||
|
# files created rcc
|
||||||
|
RCC_DIR = rcc
|
||||||
|
|
||||||
|
# files created uic
|
||||||
|
UI_DIR = uic
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
qmuparser.cpp \
|
||||||
|
qmuparsertokenreader.cpp \
|
||||||
|
qmuparsererror.cpp \
|
||||||
|
qmuparsercallback.cpp \
|
||||||
|
qmuparserbytecode.cpp \
|
||||||
|
qmuparserbase.cpp \
|
||||||
|
qmuparsertest.cpp \
|
||||||
|
qmuparserint.cpp \
|
||||||
|
stable.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
qmuparser.h\
|
||||||
|
qmuparser_global.h \
|
||||||
|
qmuparsertokenreader.h \
|
||||||
|
qmuparsertoken.h \
|
||||||
|
qmuparserstack.h \
|
||||||
|
qmuparserfixes.h \
|
||||||
|
qmuparsererror.h \
|
||||||
|
qmuparserdef.h \
|
||||||
|
qmuparsercallback.h \
|
||||||
|
qmuparserbytecode.h \
|
||||||
|
qmuparserbase.h \
|
||||||
|
qmuparsertest.h \
|
||||||
|
qmuparsertemplatemagic.h \
|
||||||
|
qmuparserint.h \
|
||||||
|
stable.h
|
||||||
|
|
||||||
|
VERSION = 2.2.3
|
||||||
|
|
||||||
|
unix {
|
||||||
|
target.path = /usr/lib
|
||||||
|
INSTALLS += target
|
||||||
|
|
||||||
|
QMAKE_CXX = ccache g++
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG += precompile_header
|
||||||
|
# Precompiled headers (PCH)
|
||||||
|
PRECOMPILED_HEADER = stable.h
|
||||||
|
win32-msvc* {
|
||||||
|
PRECOMPILED_SOURCE = stable.cpp
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG(debug, debug|release){
|
||||||
|
# Debug
|
||||||
|
unix {
|
||||||
|
*-g++{
|
||||||
|
QMAKE_CXXFLAGS += -isystem "/usr/include/qt5" -isystem "/usr/include/qt5/QtCore" -isystem "$${UI_DIR}" \
|
||||||
|
-isystem "$${MOC_DIR}" -isystem "$${RCC_DIR}" \
|
||||||
|
-O0 -Wall -Wextra -pedantic -Weffc++ -Woverloaded-virtual -Wctor-dtor-privacy \
|
||||||
|
-Wnon-virtual-dtor -Wold-style-cast -Wconversion -Winit-self -Wstack-protector \
|
||||||
|
-Wunreachable-code -Wcast-align -Wcast-qual -Wdisabled-optimization -Wfloat-equal \
|
||||||
|
-Wformat=2 -Wimport \
|
||||||
|
-Winvalid-pch -Wunsafe-loop-optimizations -Wlong-long -Wmissing-format-attribute \
|
||||||
|
-Wmissing-include-dirs -Wpacked -Wredundant-decls -Winline \
|
||||||
|
-Wswitch-default -Wswitch-enum -Wuninitialized -Wvariadic-macros \
|
||||||
|
-Wlogical-op -Wnoexcept -Wmissing-noreturn -Wpointer-arith\
|
||||||
|
-Wstrict-null-sentinel -Wstrict-overflow=5 -Wundef -Wno-unused -gdwarf-3
|
||||||
|
-ftrapv
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*-g++{#Don't use additional GCC keys on Windows system.
|
||||||
|
QMAKE_CXXFLAGS += -O0 -Wall -Wextra -pedantic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
# Release
|
||||||
|
*-g++{
|
||||||
|
QMAKE_CXXFLAGS += -O2
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINES += QT_NO_DEBUG_OUTPUT
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove generated files at cleaning
|
||||||
|
QMAKE_DISTCLEAN += $${DESTDIR}/* \
|
||||||
|
$${OBJECTS_DIR}/* \
|
||||||
|
$${UI_DIR}/* \
|
||||||
|
$${MOC_DIR}/* \
|
||||||
|
$${RCC_DIR}/*
|
34
src/libs/qmuparser/qmuparser_global.h
Normal file
34
src/libs/qmuparser/qmuparser_global.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPARSER_GLOBAL_H
|
||||||
|
#define QMUPARSER_GLOBAL_H
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
|
#if defined(QMUPARSER_LIBRARY)
|
||||||
|
# define QMUPARSERSHARED_EXPORT Q_DECL_EXPORT
|
||||||
|
#else
|
||||||
|
# define QMUPARSERSHARED_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // QMUPARSER_GLOBAL_H
|
1772
src/libs/qmuparser/qmuparserbase.cpp
Normal file
1772
src/libs/qmuparser/qmuparserbase.cpp
Normal file
File diff suppressed because it is too large
Load Diff
309
src/libs/qmuparser/qmuparserbase.h
Normal file
309
src/libs/qmuparser/qmuparserbase.h
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUQPARSERBASE_H
|
||||||
|
#define QMUQPARSERBASE_H
|
||||||
|
|
||||||
|
//--- Standard includes ------------------------------------------------------------------------
|
||||||
|
#include <cmath>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
|
//--- Parser includes --------------------------------------------------------------------------
|
||||||
|
#include "qmuparserdef.h"
|
||||||
|
#include "qmuparserstack.h"
|
||||||
|
#include "qmuparsertokenreader.h"
|
||||||
|
#include "qmuparserbytecode.h"
|
||||||
|
#include "qmuparsererror.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
/** \file
|
||||||
|
\brief This file contains the class definition of the qmuparser engine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/** \brief Mathematical expressions parser (base parser engine).
|
||||||
|
\author (C) 2013 Ingo Berg
|
||||||
|
|
||||||
|
This is the implementation of a bytecode based mathematical expressions parser.
|
||||||
|
The formula will be parsed from string and converted into a bytecode.
|
||||||
|
Future calculations will be done with the bytecode instead the formula string
|
||||||
|
resulting in a significant performance increase.
|
||||||
|
Complementary to a set of internally implemented functions the parser is able to handle
|
||||||
|
user defined functions and variables.
|
||||||
|
*/
|
||||||
|
class QmuParserBase
|
||||||
|
{
|
||||||
|
friend class QmuParserTokenReader;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** \brief Typedef for the parse functions.
|
||||||
|
|
||||||
|
The parse function do the actual work. The parser exchanges
|
||||||
|
the function pointer to the parser function depending on
|
||||||
|
which state it is in. (i.e. bytecode parser vs. string parser)
|
||||||
|
*/
|
||||||
|
typedef value_type (QmuParserBase::*ParseFunction)() const;
|
||||||
|
|
||||||
|
/** \brief Type used for storing an array of values. */
|
||||||
|
typedef std::vector<value_type> valbuf_type;
|
||||||
|
|
||||||
|
/** \brief Type for a vector of strings. */
|
||||||
|
typedef std::vector<string_type> stringbuf_type;
|
||||||
|
|
||||||
|
/** \brief Typedef for the token reader. */
|
||||||
|
typedef QmuParserTokenReader token_reader_type;
|
||||||
|
|
||||||
|
/** \brief Type used for parser tokens. */
|
||||||
|
typedef QmuParserToken<value_type, string_type> token_type;
|
||||||
|
|
||||||
|
/** \brief Maximum number of threads spawned by OpenMP when using the bulk mode. */
|
||||||
|
static const int s_MaxNumOpenMPThreads = 4;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** \brief Type of the error class.
|
||||||
|
|
||||||
|
Included for backwards compatibility.
|
||||||
|
*/
|
||||||
|
typedef QmuParserError exception_type;
|
||||||
|
|
||||||
|
static void EnableDebugDump(bool bDumpCmd, bool bDumpStack);
|
||||||
|
|
||||||
|
QmuParserBase();
|
||||||
|
QmuParserBase(const QmuParserBase &a_Parser);
|
||||||
|
QmuParserBase& operator=(const QmuParserBase &a_Parser);
|
||||||
|
|
||||||
|
virtual ~QmuParserBase();
|
||||||
|
|
||||||
|
value_type Eval() const;
|
||||||
|
value_type* Eval(int &nStackSize) const;
|
||||||
|
void Eval(value_type *results, int nBulkSize);
|
||||||
|
|
||||||
|
int GetNumResults() const;
|
||||||
|
|
||||||
|
void SetExpr(const string_type &a_sExpr);
|
||||||
|
void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL);
|
||||||
|
|
||||||
|
void SetDecSep(char_type cDecSep);
|
||||||
|
void SetThousandsSep(char_type cThousandsSep = 0);
|
||||||
|
void ResetLocale();
|
||||||
|
|
||||||
|
void EnableOptimizer(bool a_bIsOn=true);
|
||||||
|
void EnableBuiltInOprt(bool a_bIsOn=true);
|
||||||
|
|
||||||
|
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)
|
||||||
|
\brief Define a parser function without arguments.
|
||||||
|
\param a_strName Name of the function
|
||||||
|
\param a_pFun Pointer to the callback function
|
||||||
|
\param a_bAllowOpt A flag indicating this function may be optimized
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
void DefineFun(const string_type &a_strName, T a_pFun, bool a_bAllowOpt = true)
|
||||||
|
{
|
||||||
|
AddCallback( a_strName, QmuParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefineOprt(const string_type &a_strName,
|
||||||
|
fun_type2 a_pFun,
|
||||||
|
unsigned a_iPri=0,
|
||||||
|
EOprtAssociativity a_eAssociativity = oaLEFT,
|
||||||
|
bool a_bAllowOpt = false);
|
||||||
|
void DefineConst(const string_type &a_sName, value_type a_fVal);
|
||||||
|
void DefineStrConst(const string_type &a_sName, const string_type &a_strVal);
|
||||||
|
void DefineVar(const string_type &a_sName, value_type *a_fVar);
|
||||||
|
void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true);
|
||||||
|
void DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, bool a_bAllowOpt=true);
|
||||||
|
|
||||||
|
// Clear user defined variables, constants or functions
|
||||||
|
void ClearVar();
|
||||||
|
void ClearFun();
|
||||||
|
void ClearConst();
|
||||||
|
void ClearInfixOprt();
|
||||||
|
void ClearPostfixOprt();
|
||||||
|
void ClearOprt();
|
||||||
|
|
||||||
|
void RemoveVar(const string_type &a_strVarName);
|
||||||
|
const varmap_type& GetUsedVar() const;
|
||||||
|
const varmap_type& GetVar() const;
|
||||||
|
const valmap_type& GetConst() const;
|
||||||
|
const string_type& GetExpr() const;
|
||||||
|
const funmap_type& GetFunDef() const;
|
||||||
|
string_type GetVersion(EParserVersionInfo eInfo = pviFULL) const;
|
||||||
|
|
||||||
|
const char_type ** GetOprtDef() const;
|
||||||
|
void DefineNameChars(const char_type *a_szCharset);
|
||||||
|
void DefineOprtChars(const char_type *a_szCharset);
|
||||||
|
void DefineInfixOprtChars(const char_type *a_szCharset);
|
||||||
|
|
||||||
|
const char_type* ValidNameChars() const;
|
||||||
|
const char_type* ValidOprtChars() const;
|
||||||
|
const char_type* ValidInfixOprtChars() const;
|
||||||
|
|
||||||
|
void SetArgSep(char_type cArgSep);
|
||||||
|
char_type GetArgSep() const;
|
||||||
|
|
||||||
|
void Error(EErrorCodes a_iErrc,
|
||||||
|
int a_iPos = (int)qmu::string_type::npos,
|
||||||
|
const string_type &a_strTok = string_type() ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
virtual void InitCharSets() = 0;
|
||||||
|
virtual void InitFun() = 0;
|
||||||
|
virtual void InitConst() = 0;
|
||||||
|
virtual void InitOprt() = 0;
|
||||||
|
|
||||||
|
virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd);
|
||||||
|
|
||||||
|
static const char_type *c_DefaultOprt[];
|
||||||
|
static std::locale s_locale; ///< The locale used by the parser
|
||||||
|
static bool g_DbgDumpCmdCode;
|
||||||
|
static bool g_DbgDumpStack;
|
||||||
|
|
||||||
|
/** \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_nGroup(nGroup)
|
||||||
|
,m_cDecPoint(cDecSep)
|
||||||
|
,m_cThousandsSep(cThousandsSep)
|
||||||
|
{}
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void Assign(const QmuParserBase &a_Parser);
|
||||||
|
void InitTokenReader();
|
||||||
|
void ReInit() const;
|
||||||
|
|
||||||
|
void AddCallback( const string_type &a_strName,
|
||||||
|
const QmuParserCallback &a_Callback,
|
||||||
|
funmap_type &a_Storage,
|
||||||
|
const char_type *a_szCharSet );
|
||||||
|
|
||||||
|
void ApplyRemainingOprt(QmuParserStack<token_type> &a_stOpt,
|
||||||
|
QmuParserStack<token_type> &a_stVal) const;
|
||||||
|
void ApplyBinOprt(QmuParserStack<token_type> &a_stOpt,
|
||||||
|
QmuParserStack<token_type> &a_stVal) const;
|
||||||
|
|
||||||
|
void ApplyIfElse(QmuParserStack<token_type> &a_stOpt,
|
||||||
|
QmuParserStack<token_type> &a_stVal) const;
|
||||||
|
|
||||||
|
void ApplyFunc(QmuParserStack<token_type> &a_stOpt,
|
||||||
|
QmuParserStack<token_type> &a_stVal,
|
||||||
|
int iArgCount) const;
|
||||||
|
|
||||||
|
token_type ApplyStrFunc(const token_type &a_FunTok,
|
||||||
|
const std::vector<token_type> &a_vArg) const;
|
||||||
|
|
||||||
|
int GetOprtPrecedence(const token_type &a_Tok) const;
|
||||||
|
EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const;
|
||||||
|
|
||||||
|
void CreateRPN() const;
|
||||||
|
|
||||||
|
value_type ParseString() const;
|
||||||
|
value_type ParseCmdCode() const;
|
||||||
|
value_type ParseCmdCodeBulk(int nOffset, int nThreadID) const;
|
||||||
|
|
||||||
|
void CheckName(const string_type &a_strName, const string_type &a_CharSet) const;
|
||||||
|
void CheckOprt(const string_type &a_sName,
|
||||||
|
const QmuParserCallback &a_Callback,
|
||||||
|
const string_type &a_szCharSet) const;
|
||||||
|
|
||||||
|
void StackDump(const QmuParserStack<token_type > &a_stVal,
|
||||||
|
const QmuParserStack<token_type > &a_stOprt) const;
|
||||||
|
|
||||||
|
/** \brief Pointer to the parser function.
|
||||||
|
|
||||||
|
Eval() calls the function whose address is stored there.
|
||||||
|
*/
|
||||||
|
mutable ParseFunction m_pParseFormula;
|
||||||
|
mutable QmuParserByteCode m_vRPN; ///< The Bytecode class.
|
||||||
|
mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments
|
||||||
|
stringbuf_type m_vStringVarBuf;
|
||||||
|
|
||||||
|
std::auto_ptr<token_reader_type> m_pTokenReader; ///< Managed pointer to the token reader object.
|
||||||
|
|
||||||
|
funmap_type m_FunDef; ///< Map of function names and pointers.
|
||||||
|
funmap_type m_PostOprtDef; ///< Postfix operator callbacks
|
||||||
|
funmap_type m_InfixOprtDef; ///< unary infix operator.
|
||||||
|
funmap_type m_OprtDef; ///< Binary operator callbacks
|
||||||
|
valmap_type m_ConstDef; ///< user constants.
|
||||||
|
strmap_type m_StrVarDef; ///< user defined string constants
|
||||||
|
varmap_type m_VarDef; ///< user defind variables.
|
||||||
|
|
||||||
|
bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off
|
||||||
|
|
||||||
|
string_type m_sNameChars; ///< Charset for names
|
||||||
|
string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens
|
||||||
|
string_type m_sInfixOprtChars; ///< Charset for infix operator tokens
|
||||||
|
|
||||||
|
mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses
|
||||||
|
|
||||||
|
// items merely used for caching state information
|
||||||
|
mutable valbuf_type m_vStackBuffer; ///< This is merely a buffer used for the stack in the cmd parsing routine
|
||||||
|
mutable int m_nFinalResultIdx;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qmu
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
583
src/libs/qmuparser/qmuparserbytecode.cpp
Normal file
583
src/libs/qmuparser/qmuparserbytecode.cpp
Normal file
|
@ -0,0 +1,583 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "qmuparserbytecode.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <string>
|
||||||
|
#include <stack>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "qmuparserdef.h"
|
||||||
|
#include "qmuparsererror.h"
|
||||||
|
#include "qmuparsertoken.h"
|
||||||
|
#include "qmuparserstack.h"
|
||||||
|
#include "qmuparsertemplatemagic.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Bytecode default constructor. */
|
||||||
|
QmuParserByteCode::QmuParserByteCode()
|
||||||
|
:m_iStackPos(0)
|
||||||
|
,m_iMaxStackSize(0)
|
||||||
|
,m_vRPN()
|
||||||
|
,m_bEnableOptimizer(true)
|
||||||
|
{
|
||||||
|
m_vRPN.reserve(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Copy constructor.
|
||||||
|
|
||||||
|
Implemented in Terms of Assign(const QParserByteCode &a_ByteCode)
|
||||||
|
*/
|
||||||
|
QmuParserByteCode::QmuParserByteCode(const QmuParserByteCode &a_ByteCode)
|
||||||
|
{
|
||||||
|
Assign(a_ByteCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Assignment operator.
|
||||||
|
|
||||||
|
Implemented in Terms of Assign(const QParserByteCode &a_ByteCode)
|
||||||
|
*/
|
||||||
|
QmuParserByteCode& QmuParserByteCode::operator=(const QmuParserByteCode &a_ByteCode)
|
||||||
|
{
|
||||||
|
Assign(a_ByteCode);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void QmuParserByteCode::EnableOptimizer(bool bStat)
|
||||||
|
{
|
||||||
|
m_bEnableOptimizer = bStat;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Copy state of another object to this.
|
||||||
|
|
||||||
|
\throw nowthrow
|
||||||
|
*/
|
||||||
|
void QmuParserByteCode::Assign(const QmuParserByteCode &a_ByteCode)
|
||||||
|
{
|
||||||
|
if (this==&a_ByteCode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_iStackPos = a_ByteCode.m_iStackPos;
|
||||||
|
m_vRPN = a_ByteCode.m_vRPN;
|
||||||
|
m_iMaxStackSize = a_ByteCode.m_iMaxStackSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Add a Variable pointer to bytecode.
|
||||||
|
\param a_pVar Pointer to be added.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
void QmuParserByteCode::AddVar(value_type *a_pVar)
|
||||||
|
{
|
||||||
|
++m_iStackPos;
|
||||||
|
m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
|
||||||
|
|
||||||
|
// optimization does not apply
|
||||||
|
SToken tok;
|
||||||
|
tok.Cmd = cmVAR;
|
||||||
|
tok.Val.ptr = a_pVar;
|
||||||
|
tok.Val.data = 1;
|
||||||
|
tok.Val.data2 = 0;
|
||||||
|
m_vRPN.push_back(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Add a Variable pointer to bytecode.
|
||||||
|
|
||||||
|
Value entries in byte code consist of:
|
||||||
|
<ul>
|
||||||
|
<li>value array position of the value</li>
|
||||||
|
<li>the operator code according to ParserToken::cmVAL</li>
|
||||||
|
<li>the value stored in #mc_iSizeVal number of bytecode entries.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
\param a_pVal Value to be added.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
void QmuParserByteCode::AddVal(value_type a_fVal)
|
||||||
|
{
|
||||||
|
++m_iStackPos;
|
||||||
|
m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
|
||||||
|
|
||||||
|
// If optimization does not apply
|
||||||
|
SToken tok;
|
||||||
|
tok.Cmd = cmVAL;
|
||||||
|
tok.Val.ptr = NULL;
|
||||||
|
tok.Val.data = 0;
|
||||||
|
tok.Val.data2 = a_fVal;
|
||||||
|
m_vRPN.push_back(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void QmuParserByteCode::ConstantFolding(ECmdCode a_Oprt)
|
||||||
|
{
|
||||||
|
std::size_t sz = m_vRPN.size();
|
||||||
|
value_type &x = m_vRPN[sz-2].Val.data2,
|
||||||
|
&y = m_vRPN[sz-1].Val.data2;
|
||||||
|
switch (a_Oprt)
|
||||||
|
{
|
||||||
|
case cmLAND: x = (int)x && (int)y; m_vRPN.pop_back(); break;
|
||||||
|
case cmLOR: x = (int)x || (int)y; m_vRPN.pop_back(); break;
|
||||||
|
case cmLT: x = x < y; m_vRPN.pop_back(); break;
|
||||||
|
case cmGT: x = x > y; m_vRPN.pop_back(); break;
|
||||||
|
case cmLE: x = x <= y; m_vRPN.pop_back(); break;
|
||||||
|
case cmGE: x = x >= y; m_vRPN.pop_back(); break;
|
||||||
|
case cmNEQ: x = x != y; m_vRPN.pop_back(); break;
|
||||||
|
case cmEQ: x = x == y; m_vRPN.pop_back(); break;
|
||||||
|
case cmADD: x = x + y; m_vRPN.pop_back(); break;
|
||||||
|
case cmSUB: x = x - y; m_vRPN.pop_back(); break;
|
||||||
|
case cmMUL: x = x * y; m_vRPN.pop_back(); break;
|
||||||
|
case cmDIV:
|
||||||
|
|
||||||
|
#if defined(MUP_MATH_EXCEPTIONS)
|
||||||
|
if (y==0)
|
||||||
|
throw ParserError(ecDIV_BY_ZERO, _T("0"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
x = x / y;
|
||||||
|
m_vRPN.pop_back();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmPOW: x = MathImpl<value_type>::Pow(x, y);
|
||||||
|
m_vRPN.pop_back();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
} // switch opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Add an operator identifier to bytecode.
|
||||||
|
|
||||||
|
Operator entries in byte code consist of:
|
||||||
|
<ul>
|
||||||
|
<li>value array position of the result</li>
|
||||||
|
<li>the operator code according to ParserToken::ECmdCode</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
\sa ParserToken::ECmdCode
|
||||||
|
*/
|
||||||
|
void QmuParserByteCode::AddOp(ECmdCode a_Oprt)
|
||||||
|
{
|
||||||
|
bool bOptimized = false;
|
||||||
|
|
||||||
|
if (m_bEnableOptimizer)
|
||||||
|
{
|
||||||
|
std::size_t sz = m_vRPN.size();
|
||||||
|
|
||||||
|
// Check for foldable constants like:
|
||||||
|
// cmVAL cmVAL cmADD
|
||||||
|
// where cmADD can stand fopr any binary operator applied to
|
||||||
|
// two constant values.
|
||||||
|
if (sz>=2 && m_vRPN[sz-2].Cmd == cmVAL && m_vRPN[sz-1].Cmd == cmVAL)
|
||||||
|
{
|
||||||
|
ConstantFolding(a_Oprt);
|
||||||
|
bOptimized = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch(a_Oprt)
|
||||||
|
{
|
||||||
|
case cmPOW:
|
||||||
|
// Optimization for ploynomials of low order
|
||||||
|
if (m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-1].Cmd == cmVAL)
|
||||||
|
{
|
||||||
|
if (m_vRPN[sz-1].Val.data2==2)
|
||||||
|
m_vRPN[sz-2].Cmd = cmVARPOW2;
|
||||||
|
else if (m_vRPN[sz-1].Val.data2==3)
|
||||||
|
m_vRPN[sz-2].Cmd = cmVARPOW3;
|
||||||
|
else if (m_vRPN[sz-1].Val.data2==4)
|
||||||
|
m_vRPN[sz-2].Cmd = cmVARPOW4;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
m_vRPN.pop_back();
|
||||||
|
bOptimized = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmSUB:
|
||||||
|
case cmADD:
|
||||||
|
// Simple optimization based on pattern recognition for a shitload of different
|
||||||
|
// bytecode combinations of addition/subtraction
|
||||||
|
if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) ||
|
||||||
|
(m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) ||
|
||||||
|
(m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) ||
|
||||||
|
(m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) ||
|
||||||
|
(m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||
|
||||||
|
(m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||
|
||||||
|
(m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||
|
||||||
|
(m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) )
|
||||||
|
{
|
||||||
|
assert( (m_vRPN[sz-2].Val.ptr==NULL && m_vRPN[sz-1].Val.ptr!=NULL) ||
|
||||||
|
(m_vRPN[sz-2].Val.ptr!=NULL && m_vRPN[sz-1].Val.ptr==NULL) ||
|
||||||
|
(m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) );
|
||||||
|
|
||||||
|
m_vRPN[sz-2].Cmd = cmVARMUL;
|
||||||
|
m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); // variable
|
||||||
|
m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data2; // offset
|
||||||
|
m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data; // multiplikatior
|
||||||
|
m_vRPN.pop_back();
|
||||||
|
bOptimized = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmMUL:
|
||||||
|
if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) ||
|
||||||
|
(m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) )
|
||||||
|
{
|
||||||
|
m_vRPN[sz-2].Cmd = cmVARMUL;
|
||||||
|
m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr));
|
||||||
|
m_vRPN[sz-2].Val.data = m_vRPN[sz-2].Val.data2 + m_vRPN[sz-1].Val.data2;
|
||||||
|
m_vRPN[sz-2].Val.data2 = 0;
|
||||||
|
m_vRPN.pop_back();
|
||||||
|
bOptimized = true;
|
||||||
|
}
|
||||||
|
else if ( (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) ||
|
||||||
|
(m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) )
|
||||||
|
{
|
||||||
|
// Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2
|
||||||
|
m_vRPN[sz-2].Cmd = cmVARMUL;
|
||||||
|
m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr));
|
||||||
|
if (m_vRPN[sz-1].Cmd == cmVAL)
|
||||||
|
{
|
||||||
|
m_vRPN[sz-2].Val.data *= m_vRPN[sz-1].Val.data2;
|
||||||
|
m_vRPN[sz-2].Val.data2 *= m_vRPN[sz-1].Val.data2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_vRPN[sz-2].Val.data = m_vRPN[sz-1].Val.data * m_vRPN[sz-2].Val.data2;
|
||||||
|
m_vRPN[sz-2].Val.data2 = m_vRPN[sz-1].Val.data2 * m_vRPN[sz-2].Val.data2;
|
||||||
|
}
|
||||||
|
m_vRPN.pop_back();
|
||||||
|
bOptimized = true;
|
||||||
|
}
|
||||||
|
else if (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR &&
|
||||||
|
m_vRPN[sz-1].Val.ptr == m_vRPN[sz-2].Val.ptr)
|
||||||
|
{
|
||||||
|
// Optimization: a*a -> a^2
|
||||||
|
m_vRPN[sz-2].Cmd = cmVARPOW2;
|
||||||
|
m_vRPN.pop_back();
|
||||||
|
bOptimized = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmDIV:
|
||||||
|
if (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-1].Val.data2!=0)
|
||||||
|
{
|
||||||
|
// Optimization: 4*a/2 -> 2*a
|
||||||
|
m_vRPN[sz-2].Val.data /= m_vRPN[sz-1].Val.data2;
|
||||||
|
m_vRPN[sz-2].Val.data2 /= m_vRPN[sz-1].Val.data2;
|
||||||
|
m_vRPN.pop_back();
|
||||||
|
bOptimized = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
} // switch a_Oprt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If optimization can't be applied just write the value
|
||||||
|
if (!bOptimized)
|
||||||
|
{
|
||||||
|
--m_iStackPos;
|
||||||
|
SToken tok;
|
||||||
|
tok.Cmd = a_Oprt;
|
||||||
|
m_vRPN.push_back(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void QmuParserByteCode::AddIfElse(ECmdCode a_Oprt)
|
||||||
|
{
|
||||||
|
SToken tok;
|
||||||
|
tok.Cmd = a_Oprt;
|
||||||
|
m_vRPN.push_back(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Add an assignement operator
|
||||||
|
|
||||||
|
Operator entries in byte code consist of:
|
||||||
|
<ul>
|
||||||
|
<li>cmASSIGN code</li>
|
||||||
|
<li>the pointer of the destination variable</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
\sa ParserToken::ECmdCode
|
||||||
|
*/
|
||||||
|
void QmuParserByteCode::AddAssignOp(value_type *a_pVar)
|
||||||
|
{
|
||||||
|
--m_iStackPos;
|
||||||
|
|
||||||
|
SToken tok;
|
||||||
|
tok.Cmd = cmASSIGN;
|
||||||
|
tok.Val.ptr = a_pVar;
|
||||||
|
m_vRPN.push_back(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Add function to bytecode.
|
||||||
|
|
||||||
|
\param a_iArgc Number of arguments, negative numbers indicate multiarg functions.
|
||||||
|
\param a_pFun Pointer to function callback.
|
||||||
|
*/
|
||||||
|
void QmuParserByteCode::AddFun(generic_fun_type a_pFun, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (a_iArgc>=0)
|
||||||
|
{
|
||||||
|
m_iStackPos = m_iStackPos - a_iArgc + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// function with unlimited number of arguments
|
||||||
|
m_iStackPos = m_iStackPos + a_iArgc + 1;
|
||||||
|
}
|
||||||
|
m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
|
||||||
|
|
||||||
|
SToken tok;
|
||||||
|
tok.Cmd = cmFUNC;
|
||||||
|
tok.Fun.argc = a_iArgc;
|
||||||
|
tok.Fun.ptr = a_pFun;
|
||||||
|
m_vRPN.push_back(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Add a bulk function to bytecode.
|
||||||
|
|
||||||
|
\param a_iArgc Number of arguments, negative numbers indicate multiarg functions.
|
||||||
|
\param a_pFun Pointer to function callback.
|
||||||
|
*/
|
||||||
|
void QmuParserByteCode::AddBulkFun(generic_fun_type a_pFun, int a_iArgc)
|
||||||
|
{
|
||||||
|
m_iStackPos = m_iStackPos - a_iArgc + 1;
|
||||||
|
m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
|
||||||
|
|
||||||
|
SToken tok;
|
||||||
|
tok.Cmd = cmFUNC_BULK;
|
||||||
|
tok.Fun.argc = a_iArgc;
|
||||||
|
tok.Fun.ptr = a_pFun;
|
||||||
|
m_vRPN.push_back(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Add Strung function entry to the parser bytecode.
|
||||||
|
\throw nothrow
|
||||||
|
|
||||||
|
A string function entry consists of the stack position of the return value,
|
||||||
|
followed by a cmSTRFUNC code, the function pointer and an index into the
|
||||||
|
string buffer maintained by the parser.
|
||||||
|
*/
|
||||||
|
void QmuParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx)
|
||||||
|
{
|
||||||
|
m_iStackPos = m_iStackPos - a_iArgc + 1;
|
||||||
|
|
||||||
|
SToken tok;
|
||||||
|
tok.Cmd = cmFUNC_STR;
|
||||||
|
tok.Fun.argc = a_iArgc;
|
||||||
|
tok.Fun.idx = a_iIdx;
|
||||||
|
tok.Fun.ptr = a_pFun;
|
||||||
|
m_vRPN.push_back(tok);
|
||||||
|
|
||||||
|
m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Add end marker to bytecode.
|
||||||
|
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
void QmuParserByteCode::Finalize()
|
||||||
|
{
|
||||||
|
SToken tok;
|
||||||
|
tok.Cmd = cmEND;
|
||||||
|
m_vRPN.push_back(tok);
|
||||||
|
rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit
|
||||||
|
|
||||||
|
// Determine the if-then-else jump offsets
|
||||||
|
QmuParserStack<int> stIf, stElse;
|
||||||
|
int idx;
|
||||||
|
for (int i=0; i<(int)m_vRPN.size(); ++i)
|
||||||
|
{
|
||||||
|
switch(m_vRPN[i].Cmd)
|
||||||
|
{
|
||||||
|
case cmIF:
|
||||||
|
stIf.push(i);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmELSE:
|
||||||
|
stElse.push(i);
|
||||||
|
idx = stIf.pop();
|
||||||
|
m_vRPN[idx].Oprt.offset = i - idx;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmENDIF:
|
||||||
|
idx = stElse.pop();
|
||||||
|
m_vRPN[idx].Oprt.offset = i - idx;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
const SToken* QmuParserByteCode::GetBase() const
|
||||||
|
{
|
||||||
|
if (m_vRPN.size()==0)
|
||||||
|
throw QmuParserError(ecINTERNAL_ERROR);
|
||||||
|
else
|
||||||
|
return &m_vRPN[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
std::size_t QmuParserByteCode::GetMaxStackSize() const
|
||||||
|
{
|
||||||
|
return m_iMaxStackSize+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Returns the number of entries in the bytecode. */
|
||||||
|
std::size_t QmuParserByteCode::GetSize() const
|
||||||
|
{
|
||||||
|
return m_vRPN.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Delete the bytecode.
|
||||||
|
|
||||||
|
\throw nothrow
|
||||||
|
|
||||||
|
The name of this function is a violation of my own coding guidelines
|
||||||
|
but this way it's more in line with the STL functions thus more
|
||||||
|
intuitive.
|
||||||
|
*/
|
||||||
|
void QmuParserByteCode::clear()
|
||||||
|
{
|
||||||
|
m_vRPN.clear();
|
||||||
|
m_iStackPos = 0;
|
||||||
|
m_iMaxStackSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Dump bytecode (for debugging only!). */
|
||||||
|
void QmuParserByteCode::AsciiDump()
|
||||||
|
{
|
||||||
|
if (!m_vRPN.size())
|
||||||
|
{
|
||||||
|
mu::console() << _T("No bytecode available\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mu::console() << _T("Number of RPN tokens:") << (int)m_vRPN.size() << _T("\n");
|
||||||
|
for (std::size_t i=0; i<m_vRPN.size() && m_vRPN[i].Cmd!=cmEND; ++i)
|
||||||
|
{
|
||||||
|
mu::console() << std::dec << i << _T(" : \t");
|
||||||
|
switch (m_vRPN[i].Cmd)
|
||||||
|
{
|
||||||
|
case cmVAL: mu::console() << _T("VAL \t");
|
||||||
|
mu::console() << _T("[") << m_vRPN[i].Val.data2 << _T("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmVAR: mu::console() << _T("VAR \t");
|
||||||
|
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmVARPOW2: mu::console() << _T("VARPOW2 \t");
|
||||||
|
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmVARPOW3: mu::console() << _T("VARPOW3 \t");
|
||||||
|
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmVARPOW4: mu::console() << _T("VARPOW4 \t");
|
||||||
|
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmVARMUL: mu::console() << _T("VARMUL \t");
|
||||||
|
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]");
|
||||||
|
mu::console() << _T(" * [") << m_vRPN[i].Val.data << _T("]");
|
||||||
|
mu::console() << _T(" + [") << m_vRPN[i].Val.data2 << _T("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmFUNC: mu::console() << _T("CALL\t");
|
||||||
|
mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");
|
||||||
|
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Fun.ptr << _T("]");
|
||||||
|
mu::console() << _T("\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmFUNC_STR:
|
||||||
|
mu::console() << _T("CALL STRFUNC\t");
|
||||||
|
mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");
|
||||||
|
mu::console() << _T("[IDX:") << std::dec << m_vRPN[i].Fun.idx << _T("]");
|
||||||
|
mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Fun.ptr << _T("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmLT: mu::console() << _T("LT\n"); break;
|
||||||
|
case cmGT: mu::console() << _T("GT\n"); break;
|
||||||
|
case cmLE: mu::console() << _T("LE\n"); break;
|
||||||
|
case cmGE: mu::console() << _T("GE\n"); break;
|
||||||
|
case cmEQ: mu::console() << _T("EQ\n"); break;
|
||||||
|
case cmNEQ: mu::console() << _T("NEQ\n"); break;
|
||||||
|
case cmADD: mu::console() << _T("ADD\n"); break;
|
||||||
|
case cmLAND: mu::console() << _T("&&\n"); break;
|
||||||
|
case cmLOR: mu::console() << _T("||\n"); break;
|
||||||
|
case cmSUB: mu::console() << _T("SUB\n"); break;
|
||||||
|
case cmMUL: mu::console() << _T("MUL\n"); break;
|
||||||
|
case cmDIV: mu::console() << _T("DIV\n"); break;
|
||||||
|
case cmPOW: mu::console() << _T("POW\n"); break;
|
||||||
|
|
||||||
|
case cmIF: mu::console() << _T("IF\t");
|
||||||
|
mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmELSE: mu::console() << _T("ELSE\t");
|
||||||
|
mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmENDIF: mu::console() << _T("ENDIF\n"); break;
|
||||||
|
|
||||||
|
case cmASSIGN:
|
||||||
|
mu::console() << _T("ASSIGN\t");
|
||||||
|
mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Oprt.ptr << _T("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: mu::console() << _T("(unknown code: ") << m_vRPN[i].Cmd << _T(")\n");
|
||||||
|
break;
|
||||||
|
} // switch cmdCode
|
||||||
|
} // while bytecode
|
||||||
|
|
||||||
|
mu::console() << _T("END") << std::endl;
|
||||||
|
}
|
||||||
|
} // namespace qmu
|
139
src/libs/qmuparser/qmuparserbytecode.h
Normal file
139
src/libs/qmuparser/qmuparserbytecode.h
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPARSERBYTECODE_H
|
||||||
|
#define QMUPARSERBYTECODE_H
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <string>
|
||||||
|
#include <stack>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "qmuparserdef.h"
|
||||||
|
#include "qmuparsererror.h"
|
||||||
|
#include "qmuparsertoken.h"
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief Definition of the parser bytecode class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
struct SToken
|
||||||
|
{
|
||||||
|
ECmdCode Cmd;
|
||||||
|
int StackPos;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct //SValData
|
||||||
|
{
|
||||||
|
value_type *ptr;
|
||||||
|
value_type data;
|
||||||
|
value_type data2;
|
||||||
|
} Val;
|
||||||
|
|
||||||
|
struct //SFunData
|
||||||
|
{
|
||||||
|
// Note: generic_fun_type is merely a placeholder. The real type could be
|
||||||
|
// anything between gun_type1 and fun_type9. I can't use a void
|
||||||
|
// pointer due to constraints in the ANSI standard which allows
|
||||||
|
// data pointers and function pointers to differ in size.
|
||||||
|
generic_fun_type ptr;
|
||||||
|
int argc;
|
||||||
|
int idx;
|
||||||
|
} Fun;
|
||||||
|
|
||||||
|
struct //SOprtData
|
||||||
|
{
|
||||||
|
value_type *ptr;
|
||||||
|
int offset;
|
||||||
|
} Oprt;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Bytecode implementation of the Math Parser.
|
||||||
|
|
||||||
|
The bytecode contains the formula converted to revers polish notation stored in a continious
|
||||||
|
memory area. Associated with this data are operator codes, variable pointers, constant
|
||||||
|
values and function pointers. Those are necessary in order to calculate the result.
|
||||||
|
All those data items will be casted to the underlying datatype of the bytecode.
|
||||||
|
|
||||||
|
\author (C) 2004-2013 Ingo Berg
|
||||||
|
*/
|
||||||
|
class QmuParserByteCode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** \brief Token type for internal use only. */
|
||||||
|
typedef QmuParserToken<value_type, string_type> token_type;
|
||||||
|
|
||||||
|
/** \brief Token vector for storing the RPN. */
|
||||||
|
typedef std::vector<SToken> rpn_type;
|
||||||
|
|
||||||
|
/** \brief Position in the Calculation array. */
|
||||||
|
unsigned m_iStackPos;
|
||||||
|
|
||||||
|
/** \brief Maximum size needed for the stack. */
|
||||||
|
std::size_t m_iMaxStackSize;
|
||||||
|
|
||||||
|
/** \brief The actual rpn storage. */
|
||||||
|
rpn_type m_vRPN;
|
||||||
|
|
||||||
|
bool m_bEnableOptimizer;
|
||||||
|
|
||||||
|
void ConstantFolding(ECmdCode a_Oprt);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
QmuParserByteCode();
|
||||||
|
QmuParserByteCode(const QmuParserByteCode &a_ByteCode);
|
||||||
|
QmuParserByteCode& operator=(const QmuParserByteCode &a_ByteCode);
|
||||||
|
void Assign(const QmuParserByteCode &a_ByteCode);
|
||||||
|
|
||||||
|
void AddVar(value_type *a_pVar);
|
||||||
|
void AddVal(value_type a_fVal);
|
||||||
|
void AddOp(ECmdCode a_Oprt);
|
||||||
|
void AddIfElse(ECmdCode a_Oprt);
|
||||||
|
void AddAssignOp(value_type *a_pVar);
|
||||||
|
void AddFun(generic_fun_type a_pFun, int a_iArgc);
|
||||||
|
void AddBulkFun(generic_fun_type a_pFun, int a_iArgc);
|
||||||
|
void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx);
|
||||||
|
|
||||||
|
void EnableOptimizer(bool bStat);
|
||||||
|
|
||||||
|
void Finalize();
|
||||||
|
void clear();
|
||||||
|
std::size_t GetMaxStackSize() const;
|
||||||
|
std::size_t GetSize() const;
|
||||||
|
|
||||||
|
const SToken* GetBase() const;
|
||||||
|
void AsciiDump();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qmu
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
460
src/libs/qmuparser/qmuparsercallback.cpp
Normal file
460
src/libs/qmuparser/qmuparsercallback.cpp
Normal file
|
@ -0,0 +1,460 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "qmuparsercallback.h"
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief Implementation of the parser callback class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type0 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(0)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(1)
|
||||||
|
,m_iPri(a_iPrec)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(a_iCode)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Constructor for constructing funcstion callbacks taking two arguments.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type2 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(2)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Constructor for constructing binary operator callbacks.
|
||||||
|
\param a_pFun Pointer to a static function taking two arguments
|
||||||
|
\param a_bAllowOpti A flag indicating this funcation can be optimized
|
||||||
|
\param a_iPrec The operator precedence
|
||||||
|
\param a_eOprtAsct The operators associativity
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type2 a_pFun,
|
||||||
|
bool a_bAllowOpti,
|
||||||
|
int a_iPrec,
|
||||||
|
EOprtAssociativity a_eOprtAsct)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(2)
|
||||||
|
,m_iPri(a_iPrec)
|
||||||
|
,m_eOprtAsct(a_eOprtAsct)
|
||||||
|
,m_iCode(cmOPRT_BIN)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type3 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(3)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type4 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(4)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type5 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(5)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type6 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(6)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type7 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(7)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type8 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(8)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type9 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(9)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(fun_type10 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(10)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(0)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(1)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Constructor for constructing funcstion callbacks taking two arguments.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(2)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(3)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(4)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(5)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(6)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(7)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(8)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(9)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(10)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_BULK)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(multfun_type a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(-1)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC)
|
||||||
|
,m_iType(tpDBL)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(0)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_STR)
|
||||||
|
,m_iType(tpSTR)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(1)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_STR)
|
||||||
|
,m_iType(tpSTR)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserCallback::QmuParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti)
|
||||||
|
:m_pFun((void*)a_pFun)
|
||||||
|
,m_iArgc(2)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmFUNC_STR)
|
||||||
|
,m_iType(tpSTR)
|
||||||
|
,m_bAllowOpti(a_bAllowOpti)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Default constructor.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
QmuParserCallback::QmuParserCallback()
|
||||||
|
:m_pFun(0)
|
||||||
|
,m_iArgc(0)
|
||||||
|
,m_iPri(-1)
|
||||||
|
,m_eOprtAsct(oaNONE)
|
||||||
|
,m_iCode(cmUNKNOWN)
|
||||||
|
,m_iType(tpVOID)
|
||||||
|
,m_bAllowOpti(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Copy constructor.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
QmuParserCallback::QmuParserCallback(const QmuParserCallback &ref)
|
||||||
|
{
|
||||||
|
m_pFun = ref.m_pFun;
|
||||||
|
m_iArgc = ref.m_iArgc;
|
||||||
|
m_bAllowOpti = ref.m_bAllowOpti;
|
||||||
|
m_iCode = ref.m_iCode;
|
||||||
|
m_iType = ref.m_iType;
|
||||||
|
m_iPri = ref.m_iPri;
|
||||||
|
m_eOprtAsct = ref.m_eOprtAsct;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Clone this instance and return a pointer to the new instance. */
|
||||||
|
QmuParserCallback* QmuParserCallback::Clone() const
|
||||||
|
{
|
||||||
|
return new QmuParserCallback(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Return tru if the function is conservative.
|
||||||
|
|
||||||
|
Conservative functions return always the same result for the same argument.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
bool QmuParserCallback::IsOptimizable() const
|
||||||
|
{
|
||||||
|
return m_bAllowOpti;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Get the callback address for the parser function.
|
||||||
|
|
||||||
|
The type of the address is void. It needs to be recasted according to the
|
||||||
|
argument number to the right type.
|
||||||
|
|
||||||
|
\throw nothrow
|
||||||
|
\return #pFun
|
||||||
|
*/
|
||||||
|
void* QmuParserCallback::GetAddr() const
|
||||||
|
{
|
||||||
|
return m_pFun;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Return the callback code. */
|
||||||
|
ECmdCode QmuParserCallback::GetCode() const
|
||||||
|
{
|
||||||
|
return m_iCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
ETypeCode QmuParserCallback::GetType() const
|
||||||
|
{
|
||||||
|
return m_iType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Return the operator precedence.
|
||||||
|
\throw nothrown
|
||||||
|
|
||||||
|
Only valid if the callback token is an operator token (binary or infix).
|
||||||
|
*/
|
||||||
|
int QmuParserCallback::GetPri() const
|
||||||
|
{
|
||||||
|
return m_iPri;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Return the operators associativity.
|
||||||
|
\throw nothrown
|
||||||
|
|
||||||
|
Only valid if the callback token is a binary operator token.
|
||||||
|
*/
|
||||||
|
EOprtAssociativity QmuParserCallback::GetAssociativity() const
|
||||||
|
{
|
||||||
|
return m_eOprtAsct;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Returns the number of function Arguments. */
|
||||||
|
int QmuParserCallback::GetArgc() const
|
||||||
|
{
|
||||||
|
return m_iArgc;
|
||||||
|
}
|
||||||
|
} // namespace qmu
|
115
src/libs/qmuparser/qmuparsercallback.h
Normal file
115
src/libs/qmuparser/qmuparsercallback.h
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPARSERCALLBACK_H
|
||||||
|
#define QMUPARSERCALLBACK_H
|
||||||
|
|
||||||
|
#include "qmuparserdef.h"
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief Definition of the parser callback class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Encapsulation of prototypes for a numerical parser function.
|
||||||
|
|
||||||
|
Encapsulates the prototyp for numerical parser functions. The class
|
||||||
|
stores the number of arguments for parser functions as well
|
||||||
|
as additional flags indication the function is non optimizeable.
|
||||||
|
The pointer to the callback function pointer is stored as void*
|
||||||
|
and needs to be casted according to the argument count.
|
||||||
|
Negative argument counts indicate a parser function with a variable number
|
||||||
|
of arguments.
|
||||||
|
|
||||||
|
\author (C) 2004-2011 Ingo Berg
|
||||||
|
*/
|
||||||
|
class QmuParserCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QmuParserCallback(fun_type0 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC);
|
||||||
|
QmuParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity);
|
||||||
|
QmuParserCallback(fun_type2 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(fun_type3 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(fun_type4 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(fun_type5 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(fun_type6 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(fun_type7 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(fun_type8 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(fun_type9 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(fun_type10 a_pFun, bool a_bAllowOpti);
|
||||||
|
|
||||||
|
QmuParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti);
|
||||||
|
|
||||||
|
QmuParserCallback(multfun_type a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti);
|
||||||
|
QmuParserCallback();
|
||||||
|
QmuParserCallback(const QmuParserCallback &a_Fun);
|
||||||
|
|
||||||
|
QmuParserCallback* Clone() const;
|
||||||
|
|
||||||
|
bool IsOptimizable() const;
|
||||||
|
void* GetAddr() const;
|
||||||
|
ECmdCode GetCode() const;
|
||||||
|
ETypeCode GetType() const;
|
||||||
|
int GetPri() const;
|
||||||
|
EOprtAssociativity GetAssociativity() const;
|
||||||
|
int GetArgc() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void *m_pFun; ///< Pointer to the callback function, casted to void
|
||||||
|
|
||||||
|
/** \brief Number of numeric function arguments
|
||||||
|
|
||||||
|
This number is negative for functions with variable number of arguments. in this cases
|
||||||
|
they represent the actual number of arguments found.
|
||||||
|
*/
|
||||||
|
int m_iArgc;
|
||||||
|
int m_iPri; ///< Valid only for binary and infix operators; Operator precedence.
|
||||||
|
EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators
|
||||||
|
ECmdCode m_iCode;
|
||||||
|
ETypeCode m_iType;
|
||||||
|
bool m_bAllowOpti; ///< Flag indication optimizeability
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Container for Callback objects. */
|
||||||
|
typedef std::map<string_type, QmuParserCallback> funmap_type;
|
||||||
|
|
||||||
|
} // namespace qmu
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
366
src/libs/qmuparser/qmuparserdef.h
Normal file
366
src/libs/qmuparser/qmuparserdef.h
Normal file
|
@ -0,0 +1,366 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPDEF_H
|
||||||
|
#define QMUPDEF_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "qmuparserfixes.h"
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief This file contains standard definitions used by the parser.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define QMUP_VERSION _T("2.2.3")
|
||||||
|
#define QMUP_VERSION_DATE _T("20121222; SF")
|
||||||
|
|
||||||
|
#define QMUP_CHARS _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
|
||||||
|
/** \brief If this macro is defined mathematical exceptions (div by zero) will be thrown as exceptions. */
|
||||||
|
//#define MUP_MATH_EXCEPTIONS
|
||||||
|
|
||||||
|
/** \brief Define the base datatype for values.
|
||||||
|
|
||||||
|
This datatype must be a built in value type. You can not use custom classes.
|
||||||
|
It should be working with all types except "int"!
|
||||||
|
*/
|
||||||
|
#define QMUP_BASETYPE double
|
||||||
|
|
||||||
|
/** \brief Activate this option in order to compile with OpenMP support.
|
||||||
|
|
||||||
|
OpenMP is used only in the bulk mode it may increase the performance a bit.
|
||||||
|
*/
|
||||||
|
//#define MUP_USE_OPENMP
|
||||||
|
|
||||||
|
#if defined(_UNICODE)
|
||||||
|
/** \brief Definition of the basic parser string type. */
|
||||||
|
#define MUP_STRING_TYPE std::wstring
|
||||||
|
|
||||||
|
#if !defined(_T)
|
||||||
|
#define _T(x) L##x
|
||||||
|
#endif // not defined _T
|
||||||
|
#else
|
||||||
|
#ifndef _T
|
||||||
|
#define _T(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \brief Definition of the basic parser string type. */
|
||||||
|
#define MUP_STRING_TYPE std::string
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_DEBUG)
|
||||||
|
/** \brief Debug macro to force an abortion of the programm with a certain message.
|
||||||
|
*/
|
||||||
|
#define MUP_FAIL(MSG) \
|
||||||
|
{ \
|
||||||
|
bool MSG=false; \
|
||||||
|
assert(MSG); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief An assertion that does not kill the program.
|
||||||
|
|
||||||
|
This macro is neutralised in UNICODE builds. It's
|
||||||
|
too difficult to translate.
|
||||||
|
*/
|
||||||
|
#define MUP_ASSERT(COND) \
|
||||||
|
if (!(COND)) \
|
||||||
|
{ \
|
||||||
|
stringstream_type ss; \
|
||||||
|
ss << _T("Assertion \"") _T(#COND) _T("\" failed: ") \
|
||||||
|
<< __FILE__ << _T(" line ") \
|
||||||
|
<< __LINE__ << _T("."); \
|
||||||
|
throw ParserError( ss.str() ); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define MUP_FAIL(MSG)
|
||||||
|
#define MUP_ASSERT(COND)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
#if defined(_UNICODE)
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Encapsulate wcout. */
|
||||||
|
inline std::wostream& console()
|
||||||
|
{
|
||||||
|
return std::wcout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Encapsulate cin. */
|
||||||
|
inline std::wistream& console_in()
|
||||||
|
{
|
||||||
|
return std::wcin;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/** \brief Encapsulate cout.
|
||||||
|
|
||||||
|
Used for supporting UNICODE more easily.
|
||||||
|
*/
|
||||||
|
inline std::ostream& console()
|
||||||
|
{
|
||||||
|
return std::cout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Encapsulate cin.
|
||||||
|
|
||||||
|
Used for supporting UNICODE more easily.
|
||||||
|
*/
|
||||||
|
inline std::istream& console_in()
|
||||||
|
{
|
||||||
|
return std::cin;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Bytecode values.
|
||||||
|
|
||||||
|
\attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt!
|
||||||
|
*/
|
||||||
|
enum ECmdCode
|
||||||
|
{
|
||||||
|
// The following are codes for built in binary operators
|
||||||
|
// apart from built in operators the user has the opportunity to
|
||||||
|
// add user defined operators.
|
||||||
|
cmLE = 0, ///< Operator item: less or equal
|
||||||
|
cmGE = 1, ///< Operator item: greater or equal
|
||||||
|
cmNEQ = 2, ///< Operator item: not equal
|
||||||
|
cmEQ = 3, ///< Operator item: equals
|
||||||
|
cmLT = 4, ///< Operator item: less than
|
||||||
|
cmGT = 5, ///< Operator item: greater than
|
||||||
|
cmADD = 6, ///< Operator item: add
|
||||||
|
cmSUB = 7, ///< Operator item: subtract
|
||||||
|
cmMUL = 8, ///< Operator item: multiply
|
||||||
|
cmDIV = 9, ///< Operator item: division
|
||||||
|
cmPOW = 10, ///< Operator item: y to the power of ...
|
||||||
|
cmLAND = 11,
|
||||||
|
cmLOR = 12,
|
||||||
|
cmASSIGN = 13, ///< Operator item: Assignment operator
|
||||||
|
cmBO = 14, ///< Operator item: opening bracket
|
||||||
|
cmBC = 15, ///< Operator item: closing bracket
|
||||||
|
cmIF = 16, ///< For use in the ternary if-then-else operator
|
||||||
|
cmELSE = 17, ///< For use in the ternary if-then-else operator
|
||||||
|
cmENDIF = 18, ///< For use in the ternary if-then-else operator
|
||||||
|
cmARG_SEP = 19, ///< function argument separator
|
||||||
|
cmVAR = 20, ///< variable item
|
||||||
|
cmVAL = 21, ///< value item
|
||||||
|
|
||||||
|
// For optimization purposes
|
||||||
|
cmVARPOW2,
|
||||||
|
cmVARPOW3,
|
||||||
|
cmVARPOW4,
|
||||||
|
cmVARMUL,
|
||||||
|
cmPOW2,
|
||||||
|
|
||||||
|
// operators and functions
|
||||||
|
cmFUNC, ///< Code for a generic function item
|
||||||
|
cmFUNC_STR, ///< Code for a function with a string parameter
|
||||||
|
cmFUNC_BULK, ///< Special callbacks for Bulk mode with an additional parameter for the bulk index
|
||||||
|
cmSTRING, ///< Code for a string token
|
||||||
|
cmOPRT_BIN, ///< user defined binary operator
|
||||||
|
cmOPRT_POSTFIX, ///< code for postfix operators
|
||||||
|
cmOPRT_INFIX, ///< code for infix operators
|
||||||
|
cmEND, ///< end of formula
|
||||||
|
cmUNKNOWN ///< uninitialized item
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Types internally used by the parser.
|
||||||
|
*/
|
||||||
|
enum ETypeCode
|
||||||
|
{
|
||||||
|
tpSTR = 0, ///< String type (Function arguments and constants only, no string variables)
|
||||||
|
tpDBL = 1, ///< Floating point variables
|
||||||
|
tpVOID = 2 ///< Undefined type.
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
enum EParserVersionInfo
|
||||||
|
{
|
||||||
|
pviBRIEF,
|
||||||
|
pviFULL
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Parser operator precedence values. */
|
||||||
|
enum EOprtAssociativity
|
||||||
|
{
|
||||||
|
oaLEFT = 0,
|
||||||
|
oaRIGHT = 1,
|
||||||
|
oaNONE = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Parser operator precedence values. */
|
||||||
|
enum EOprtPrecedence
|
||||||
|
{
|
||||||
|
// binary operators
|
||||||
|
prLOR = 1,
|
||||||
|
prLAND = 2,
|
||||||
|
prLOGIC = 3, ///< logic operators
|
||||||
|
prCMP = 4, ///< comparsion operators
|
||||||
|
prADD_SUB = 5, ///< addition
|
||||||
|
prMUL_DIV = 6, ///< multiplication/division
|
||||||
|
prPOW = 7, ///< power operator priority (highest)
|
||||||
|
|
||||||
|
// infix operators
|
||||||
|
prINFIX = 6, ///< Signs have a higher priority than ADD_SUB, but lower than power operator
|
||||||
|
prPOSTFIX = 6 ///< Postfix operator priority (currently unused)
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// basic types
|
||||||
|
|
||||||
|
/** \brief The numeric datatype used by the parser.
|
||||||
|
|
||||||
|
Normally this is a floating point type either single or double precision.
|
||||||
|
*/
|
||||||
|
typedef QMUP_BASETYPE value_type;
|
||||||
|
|
||||||
|
/** \brief The stringtype used by the parser.
|
||||||
|
|
||||||
|
Depends on wether UNICODE is used or not.
|
||||||
|
*/
|
||||||
|
typedef MUP_STRING_TYPE string_type;
|
||||||
|
|
||||||
|
/** \brief The character type used by the parser.
|
||||||
|
|
||||||
|
Depends on wether UNICODE is used or not.
|
||||||
|
*/
|
||||||
|
typedef string_type::value_type char_type;
|
||||||
|
|
||||||
|
/** \brief Typedef for easily using stringstream that respect the parser stringtype. */
|
||||||
|
typedef std::basic_stringstream<char_type,
|
||||||
|
std::char_traits<char_type>,
|
||||||
|
std::allocator<char_type> > stringstream_type;
|
||||||
|
|
||||||
|
// Data container types
|
||||||
|
|
||||||
|
/** \brief Type used for storing variables. */
|
||||||
|
typedef std::map<string_type, value_type*> varmap_type;
|
||||||
|
|
||||||
|
/** \brief Type used for storing constants. */
|
||||||
|
typedef std::map<string_type, value_type> valmap_type;
|
||||||
|
|
||||||
|
/** \brief Type for assigning a string name to an index in the internal string table. */
|
||||||
|
typedef std::map<string_type, std::size_t> strmap_type;
|
||||||
|
|
||||||
|
// Parser callbacks
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions without arguments. */
|
||||||
|
typedef value_type (*generic_fun_type)();
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions without arguments. */
|
||||||
|
typedef value_type (*fun_type0)();
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with a single arguments. */
|
||||||
|
typedef value_type (*fun_type1)(value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with two arguments. */
|
||||||
|
typedef value_type (*fun_type2)(value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with three arguments. */
|
||||||
|
typedef value_type (*fun_type3)(value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with four arguments. */
|
||||||
|
typedef value_type (*fun_type4)(value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*fun_type5)(value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*fun_type6)(value_type, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*fun_type7)(value_type, value_type, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*fun_type8)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*fun_type9)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*fun_type10)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions without arguments. */
|
||||||
|
typedef value_type (*bulkfun_type0)(int, int);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with a single arguments. */
|
||||||
|
typedef value_type (*bulkfun_type1)(int, int, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with two arguments. */
|
||||||
|
typedef value_type (*bulkfun_type2)(int, int, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with three arguments. */
|
||||||
|
typedef value_type (*bulkfun_type3)(int, int, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with four arguments. */
|
||||||
|
typedef value_type (*bulkfun_type4)(int, int, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*bulkfun_type5)(int, int, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*bulkfun_type6)(int, int, value_type, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*bulkfun_type7)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*bulkfun_type8)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*bulkfun_type9)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with five arguments. */
|
||||||
|
typedef value_type (*bulkfun_type10)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions with a variable argument list. */
|
||||||
|
typedef value_type (*multfun_type)(const value_type*, int);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions taking a string as an argument. */
|
||||||
|
typedef value_type (*strfun_type1)(const char_type*);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions taking a string and a value as arguments. */
|
||||||
|
typedef value_type (*strfun_type2)(const char_type*, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback type used for functions taking a string and two values as arguments. */
|
||||||
|
typedef value_type (*strfun_type3)(const char_type*, value_type, value_type);
|
||||||
|
|
||||||
|
/** \brief Callback used for functions that identify values in a string. */
|
||||||
|
typedef int (*identfun_type)(const char_type *sExpr, int *nPos, value_type *fVal);
|
||||||
|
|
||||||
|
/** \brief Callback used for variable creation factory functions. */
|
||||||
|
typedef value_type* (*facfun_type)(const char_type*, void*);
|
||||||
|
} // end of namespace
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
334
src/libs/qmuparser/qmuparsererror.cpp
Normal file
334
src/libs/qmuparser/qmuparsererror.cpp
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "qmuparsererror.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
const QmuParserErrorMsg QmuParserErrorMsg::m_Instance;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
const QmuParserErrorMsg& QmuParserErrorMsg::Instance()
|
||||||
|
{
|
||||||
|
return m_Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
string_type QmuParserErrorMsg::operator[](unsigned a_iIdx) const
|
||||||
|
{
|
||||||
|
return (a_iIdx<m_vErrMsg.size()) ? m_vErrMsg[a_iIdx] : string_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserErrorMsg::~QmuParserErrorMsg()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Assignement operator is deactivated.
|
||||||
|
*/
|
||||||
|
QmuParserErrorMsg& QmuParserErrorMsg::operator=(const QmuParserErrorMsg& )
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserErrorMsg::QmuParserErrorMsg(const QmuParserErrorMsg&)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserErrorMsg::QmuParserErrorMsg()
|
||||||
|
:m_vErrMsg(0)
|
||||||
|
{
|
||||||
|
m_vErrMsg.resize(ecCOUNT);
|
||||||
|
|
||||||
|
m_vErrMsg[ecUNASSIGNABLE_TOKEN] = _T("Unexpected token \"$TOK$\" found at position $POS$.");
|
||||||
|
m_vErrMsg[ecINTERNAL_ERROR] = _T("Internal error");
|
||||||
|
m_vErrMsg[ecINVALID_NAME] = _T("Invalid function-, variable- or constant name: \"$TOK$\".");
|
||||||
|
m_vErrMsg[ecINVALID_BINOP_IDENT] = _T("Invalid binary operator identifier: \"$TOK$\".");
|
||||||
|
m_vErrMsg[ecINVALID_INFIX_IDENT] = _T("Invalid infix operator identifier: \"$TOK$\".");
|
||||||
|
m_vErrMsg[ecINVALID_POSTFIX_IDENT] = _T("Invalid postfix operator identifier: \"$TOK$\".");
|
||||||
|
m_vErrMsg[ecINVALID_FUN_PTR] = _T("Invalid pointer to callback function.");
|
||||||
|
m_vErrMsg[ecEMPTY_EXPRESSION] = _T("Expression is empty.");
|
||||||
|
m_vErrMsg[ecINVALID_VAR_PTR] = _T("Invalid pointer to variable.");
|
||||||
|
m_vErrMsg[ecUNEXPECTED_OPERATOR] = _T("Unexpected operator \"$TOK$\" found at position $POS$");
|
||||||
|
m_vErrMsg[ecUNEXPECTED_EOF] = _T("Unexpected end of expression at position $POS$");
|
||||||
|
m_vErrMsg[ecUNEXPECTED_ARG_SEP] = _T("Unexpected argument separator at position $POS$");
|
||||||
|
m_vErrMsg[ecUNEXPECTED_PARENS] = _T("Unexpected parenthesis \"$TOK$\" at position $POS$");
|
||||||
|
m_vErrMsg[ecUNEXPECTED_FUN] = _T("Unexpected function \"$TOK$\" at position $POS$");
|
||||||
|
m_vErrMsg[ecUNEXPECTED_VAL] = _T("Unexpected value \"$TOK$\" found at position $POS$");
|
||||||
|
m_vErrMsg[ecUNEXPECTED_VAR] = _T("Unexpected variable \"$TOK$\" found at position $POS$");
|
||||||
|
m_vErrMsg[ecUNEXPECTED_ARG] = _T("Function arguments used without a function (position: $POS$)");
|
||||||
|
m_vErrMsg[ecMISSING_PARENS] = _T("Missing parenthesis");
|
||||||
|
m_vErrMsg[ecTOO_MANY_PARAMS] = _T("Too many parameters for function \"$TOK$\" at expression position $POS$");
|
||||||
|
m_vErrMsg[ecTOO_FEW_PARAMS] = _T("Too few parameters for function \"$TOK$\" at expression position $POS$");
|
||||||
|
m_vErrMsg[ecDIV_BY_ZERO] = _T("Divide by zero");
|
||||||
|
m_vErrMsg[ecDOMAIN_ERROR] = _T("Domain error");
|
||||||
|
m_vErrMsg[ecNAME_CONFLICT] = _T("Name conflict");
|
||||||
|
m_vErrMsg[ecOPT_PRI] = _T("Invalid value for operator priority (must be greater or equal to zero).");
|
||||||
|
m_vErrMsg[ecBUILTIN_OVERLOAD] = _T("user defined binary operator \"$TOK$\" conflicts with a built in operator.");
|
||||||
|
m_vErrMsg[ecUNEXPECTED_STR] = _T("Unexpected string token found at position $POS$.");
|
||||||
|
m_vErrMsg[ecUNTERMINATED_STRING] = _T("Unterminated string starting at position $POS$.");
|
||||||
|
m_vErrMsg[ecSTRING_EXPECTED] = _T("String function called with a non string type of argument.");
|
||||||
|
m_vErrMsg[ecVAL_EXPECTED] = _T("String value used where a numerical argument is expected.");
|
||||||
|
m_vErrMsg[ecOPRT_TYPE_CONFLICT] = _T("No suitable overload for operator \"$TOK$\" at position $POS$.");
|
||||||
|
m_vErrMsg[ecSTR_RESULT] = _T("Function result is a string.");
|
||||||
|
m_vErrMsg[ecGENERIC] = _T("Parser error.");
|
||||||
|
m_vErrMsg[ecLOCALE] = _T("Decimal separator is identic to function argument separator.");
|
||||||
|
m_vErrMsg[ecUNEXPECTED_CONDITIONAL] = _T("The \"$TOK$\" operator must be preceeded by a closing bracket.");
|
||||||
|
m_vErrMsg[ecMISSING_ELSE_CLAUSE] = _T("If-then-else operator is missing an else clause");
|
||||||
|
m_vErrMsg[ecMISPLACED_COLON] = _T("Misplaced colon at position $POS$");
|
||||||
|
|
||||||
|
#if defined(_DEBUG)
|
||||||
|
for (int i=0; i<ecCOUNT; ++i)
|
||||||
|
if (!m_vErrMsg[i].length())
|
||||||
|
assert(false);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// QParserError class
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** \brief Default constructor. */
|
||||||
|
QmuParserError::QmuParserError()
|
||||||
|
:m_strMsg()
|
||||||
|
,m_strFormula()
|
||||||
|
,m_strTok()
|
||||||
|
,m_iPos(-1)
|
||||||
|
,m_iErrc(ecUNDEFINED)
|
||||||
|
,m_ErrMsg(QmuParserErrorMsg::Instance())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief This Constructor is used for internal exceptions only.
|
||||||
|
|
||||||
|
It does not contain any information but the error code.
|
||||||
|
*/
|
||||||
|
QmuParserError::QmuParserError(EErrorCodes a_iErrc)
|
||||||
|
:m_strMsg()
|
||||||
|
,m_strFormula()
|
||||||
|
,m_strTok()
|
||||||
|
,m_iPos(-1)
|
||||||
|
,m_iErrc(a_iErrc)
|
||||||
|
,m_ErrMsg(QmuParserErrorMsg::Instance())
|
||||||
|
{
|
||||||
|
m_strMsg = m_ErrMsg[m_iErrc];
|
||||||
|
stringstream_type stream;
|
||||||
|
stream << (int)m_iPos;
|
||||||
|
ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
|
||||||
|
ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Construct an error from a message text. */
|
||||||
|
QmuParserError::QmuParserError(const string_type &sMsg)
|
||||||
|
:m_ErrMsg(QmuParserErrorMsg::Instance())
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
m_strMsg = sMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Construct an error object.
|
||||||
|
\param [in] a_iErrc the error code.
|
||||||
|
\param [in] sTok The token string related to this error.
|
||||||
|
\param [in] sExpr The expression related to the error.
|
||||||
|
\param [in] a_iPos the position in the expression where the error occured.
|
||||||
|
*/
|
||||||
|
QmuParserError::QmuParserError( EErrorCodes iErrc,
|
||||||
|
const string_type &sTok,
|
||||||
|
const string_type &sExpr,
|
||||||
|
int iPos )
|
||||||
|
:m_strMsg()
|
||||||
|
,m_strFormula(sExpr)
|
||||||
|
,m_strTok(sTok)
|
||||||
|
,m_iPos(iPos)
|
||||||
|
,m_iErrc(iErrc)
|
||||||
|
,m_ErrMsg(QmuParserErrorMsg::Instance())
|
||||||
|
{
|
||||||
|
m_strMsg = m_ErrMsg[m_iErrc];
|
||||||
|
stringstream_type stream;
|
||||||
|
stream << (int)m_iPos;
|
||||||
|
ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
|
||||||
|
ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Construct an error object.
|
||||||
|
\param [in] iErrc the error code.
|
||||||
|
\param [in] iPos the position in the expression where the error occured.
|
||||||
|
\param [in] sTok The token string related to this error.
|
||||||
|
*/
|
||||||
|
QmuParserError::QmuParserError(EErrorCodes iErrc, int iPos, const string_type &sTok)
|
||||||
|
:m_strMsg()
|
||||||
|
,m_strFormula()
|
||||||
|
,m_strTok(sTok)
|
||||||
|
,m_iPos(iPos)
|
||||||
|
,m_iErrc(iErrc)
|
||||||
|
,m_ErrMsg(QmuParserErrorMsg::Instance())
|
||||||
|
{
|
||||||
|
m_strMsg = m_ErrMsg[m_iErrc];
|
||||||
|
stringstream_type stream;
|
||||||
|
stream << (int)m_iPos;
|
||||||
|
ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
|
||||||
|
ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Construct an error object.
|
||||||
|
\param [in] szMsg The error message text.
|
||||||
|
\param [in] iPos the position related to the error.
|
||||||
|
\param [in] sTok The token string related to this error.
|
||||||
|
*/
|
||||||
|
QmuParserError::QmuParserError(const char_type *szMsg, int iPos, const string_type &sTok)
|
||||||
|
:m_strMsg(szMsg)
|
||||||
|
,m_strFormula()
|
||||||
|
,m_strTok(sTok)
|
||||||
|
,m_iPos(iPos)
|
||||||
|
,m_iErrc(ecGENERIC)
|
||||||
|
,m_ErrMsg(QmuParserErrorMsg::Instance())
|
||||||
|
{
|
||||||
|
stringstream_type stream;
|
||||||
|
stream << (int)m_iPos;
|
||||||
|
ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
|
||||||
|
ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Copy constructor. */
|
||||||
|
QmuParserError::QmuParserError(const QmuParserError &a_Obj)
|
||||||
|
:m_strMsg(a_Obj.m_strMsg)
|
||||||
|
,m_strFormula(a_Obj.m_strFormula)
|
||||||
|
,m_strTok(a_Obj.m_strTok)
|
||||||
|
,m_iPos(a_Obj.m_iPos)
|
||||||
|
,m_iErrc(a_Obj.m_iErrc)
|
||||||
|
,m_ErrMsg(QmuParserErrorMsg::Instance())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Assignment operator. */
|
||||||
|
QmuParserError& QmuParserError::operator=(const QmuParserError &a_Obj)
|
||||||
|
{
|
||||||
|
if (this==&a_Obj)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
m_strMsg = a_Obj.m_strMsg;
|
||||||
|
m_strFormula = a_Obj.m_strFormula;
|
||||||
|
m_strTok = a_Obj.m_strTok;
|
||||||
|
m_iPos = a_Obj.m_iPos;
|
||||||
|
m_iErrc = a_Obj.m_iErrc;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
QmuParserError::~QmuParserError()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Replace all ocuurences of a substring with another string.
|
||||||
|
\param strFind The string that shall be replaced.
|
||||||
|
\param strReplaceWith The string that should be inserted instead of strFind
|
||||||
|
*/
|
||||||
|
void QmuParserError::ReplaceSubString( string_type &strSource,
|
||||||
|
const string_type &strFind,
|
||||||
|
const string_type &strReplaceWith)
|
||||||
|
{
|
||||||
|
string_type strResult;
|
||||||
|
string_type::size_type iPos(0), iNext(0);
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
iNext = strSource.find(strFind, iPos);
|
||||||
|
strResult.append(strSource, iPos, iNext-iPos);
|
||||||
|
|
||||||
|
if( iNext==string_type::npos )
|
||||||
|
break;
|
||||||
|
|
||||||
|
strResult.append(strReplaceWith);
|
||||||
|
iPos = iNext + strFind.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
strSource.swap(strResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Reset the erro object. */
|
||||||
|
void QmuParserError::Reset()
|
||||||
|
{
|
||||||
|
m_strMsg = _T("");
|
||||||
|
m_strFormula = _T("");
|
||||||
|
m_strTok = _T("");
|
||||||
|
m_iPos = -1;
|
||||||
|
m_iErrc = ecUNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Set the expression related to this error. */
|
||||||
|
void QmuParserError::SetFormula(const string_type &a_strFormula)
|
||||||
|
{
|
||||||
|
m_strFormula = a_strFormula;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief gets the expression related tp this error.*/
|
||||||
|
const string_type& QmuParserError::GetExpr() const
|
||||||
|
{
|
||||||
|
return m_strFormula;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Returns the message string for this error. */
|
||||||
|
const string_type& QmuParserError::GetMsg() const
|
||||||
|
{
|
||||||
|
return m_strMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Return the formula position related to the error.
|
||||||
|
|
||||||
|
If the error is not related to a distinct position this will return -1
|
||||||
|
*/
|
||||||
|
std::size_t QmuParserError::GetPos() const
|
||||||
|
{
|
||||||
|
return m_iPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Return string related with this token (if available). */
|
||||||
|
const string_type& QmuParserError::GetToken() const
|
||||||
|
{
|
||||||
|
return m_strTok;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Return the error code. */
|
||||||
|
EErrorCodes QmuParserError::GetCode() const
|
||||||
|
{
|
||||||
|
return m_iErrc;
|
||||||
|
}
|
||||||
|
} // namespace qmu
|
171
src/libs/qmuparser/qmuparsererror.h
Normal file
171
src/libs/qmuparser/qmuparsererror.h
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPARSERERROR_H
|
||||||
|
#define QMUPARSERERROR_H
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "qmuparserdef.h"
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief This file defines the error class used by the parser.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Error codes. */
|
||||||
|
enum EErrorCodes
|
||||||
|
{
|
||||||
|
// Formula syntax errors
|
||||||
|
ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found
|
||||||
|
ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified.
|
||||||
|
ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(")
|
||||||
|
ecUNEXPECTED_ARG_SEP = 3, ///< An unexpected comma has been found. (Example: "1,23")
|
||||||
|
ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found
|
||||||
|
ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found
|
||||||
|
ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found
|
||||||
|
ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing
|
||||||
|
ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position
|
||||||
|
ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument
|
||||||
|
ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument
|
||||||
|
ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3")
|
||||||
|
ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)")
|
||||||
|
ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)")
|
||||||
|
ecTOO_MANY_PARAMS = 14, ///< Too many function parameters
|
||||||
|
ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)")
|
||||||
|
ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type
|
||||||
|
ecSTR_RESULT = 17, ///< result is a string
|
||||||
|
|
||||||
|
// Invalid Parser input Parameters
|
||||||
|
ecINVALID_NAME = 18, ///< Invalid function, variable or constant name.
|
||||||
|
ecINVALID_BINOP_IDENT = 19, ///< Invalid binary operator identifier
|
||||||
|
ecINVALID_INFIX_IDENT = 20, ///< Invalid function, variable or constant name.
|
||||||
|
ecINVALID_POSTFIX_IDENT = 21, ///< Invalid function, variable or constant name.
|
||||||
|
|
||||||
|
ecBUILTIN_OVERLOAD = 22, ///< Trying to overload builtin operator
|
||||||
|
ecINVALID_FUN_PTR = 23, ///< Invalid callback function pointer
|
||||||
|
ecINVALID_VAR_PTR = 24, ///< Invalid variable pointer
|
||||||
|
ecEMPTY_EXPRESSION = 25, ///< The Expression is empty
|
||||||
|
ecNAME_CONFLICT = 26, ///< Name conflict
|
||||||
|
ecOPT_PRI = 27, ///< Invalid operator priority
|
||||||
|
//
|
||||||
|
ecDOMAIN_ERROR = 28, ///< catch division by zero, sqrt(-1), log(0) (currently unused)
|
||||||
|
ecDIV_BY_ZERO = 29, ///< Division by zero (currently unused)
|
||||||
|
ecGENERIC = 30, ///< Generic error
|
||||||
|
ecLOCALE = 31, ///< Conflict with current locale
|
||||||
|
|
||||||
|
ecUNEXPECTED_CONDITIONAL = 32,
|
||||||
|
ecMISSING_ELSE_CLAUSE = 33,
|
||||||
|
ecMISPLACED_COLON = 34,
|
||||||
|
|
||||||
|
// internal errors
|
||||||
|
ecINTERNAL_ERROR = 35, ///< Internal error of any kind.
|
||||||
|
|
||||||
|
// The last two are special entries
|
||||||
|
ecCOUNT, ///< This is no error code, It just stores just the total number of error codes
|
||||||
|
ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief A class that handles the error messages.
|
||||||
|
*/
|
||||||
|
class QmuParserErrorMsg
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef QmuParserErrorMsg self_type;
|
||||||
|
|
||||||
|
QmuParserErrorMsg& operator=(const QmuParserErrorMsg &);
|
||||||
|
QmuParserErrorMsg(const QmuParserErrorMsg&);
|
||||||
|
QmuParserErrorMsg();
|
||||||
|
|
||||||
|
~QmuParserErrorMsg();
|
||||||
|
|
||||||
|
static const QmuParserErrorMsg& Instance();
|
||||||
|
string_type operator[](unsigned a_iIdx) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<string_type> m_vErrMsg; ///< A vector with the predefined error messages
|
||||||
|
static const self_type m_Instance; ///< The instance pointer
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Error class of the parser.
|
||||||
|
\author Ingo Berg
|
||||||
|
|
||||||
|
Part of the math parser package.
|
||||||
|
*/
|
||||||
|
class QmuParserError
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** \brief Replace all ocuurences of a substring with another string. */
|
||||||
|
void ReplaceSubString( string_type &strSource,
|
||||||
|
const string_type &strFind,
|
||||||
|
const string_type &strReplaceWith);
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
QmuParserError();
|
||||||
|
explicit QmuParserError(EErrorCodes a_iErrc);
|
||||||
|
explicit QmuParserError(const string_type &sMsg);
|
||||||
|
QmuParserError( EErrorCodes a_iErrc,
|
||||||
|
const string_type &sTok,
|
||||||
|
const string_type &sFormula = string_type(),
|
||||||
|
int a_iPos = -1);
|
||||||
|
QmuParserError( EErrorCodes a_iErrc,
|
||||||
|
int a_iPos,
|
||||||
|
const string_type &sTok);
|
||||||
|
QmuParserError( const char_type *a_szMsg,
|
||||||
|
int a_iPos = -1,
|
||||||
|
const string_type &sTok = string_type());
|
||||||
|
QmuParserError(const QmuParserError &a_Obj);
|
||||||
|
QmuParserError& operator=(const QmuParserError &a_Obj);
|
||||||
|
~QmuParserError();
|
||||||
|
|
||||||
|
void SetFormula(const string_type &a_strFormula);
|
||||||
|
const string_type& GetExpr() const;
|
||||||
|
const string_type& GetMsg() const;
|
||||||
|
std::size_t GetPos() const;
|
||||||
|
const string_type& GetToken() const;
|
||||||
|
EErrorCodes GetCode() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
string_type m_strMsg; ///< The message string
|
||||||
|
string_type m_strFormula; ///< Formula string
|
||||||
|
string_type m_strTok; ///< Token related with the error
|
||||||
|
int m_iPos; ///< Formula position related to the error
|
||||||
|
EErrorCodes m_iErrc; ///< Error code
|
||||||
|
const QmuParserErrorMsg &m_ErrMsg;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qmu
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
59
src/libs/qmuparser/qmuparserfixes.h
Normal file
59
src/libs/qmuparser/qmuparserfixes.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPARSERFIXES_H
|
||||||
|
#define QMUPARSERFIXES_H
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief This file contains compatibility fixes for some platforms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Compatibility fixes
|
||||||
|
//
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Intel Compiler
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
|
||||||
|
// remark #981: operands are evaluated in unspecified order
|
||||||
|
// disabled -> completely pointless if the functions do not have side effects
|
||||||
|
//
|
||||||
|
#pragma warning(disable:981)
|
||||||
|
|
||||||
|
// remark #383: value copied to temporary, reference to temporary used
|
||||||
|
#pragma warning(disable:383)
|
||||||
|
|
||||||
|
// remark #1572: floating-point equality and inequality comparisons are unreliable
|
||||||
|
// disabled -> everyone knows it, the parser passes this problem
|
||||||
|
// deliberately to the user
|
||||||
|
#pragma warning(disable:1572)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // include guard
|
||||||
|
|
||||||
|
|
277
src/libs/qmuparser/qmuparserint.cpp
Normal file
277
src/libs/qmuparser/qmuparserint.cpp
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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
|
||||||
|
{
|
||||||
|
value_type QmuParserInt::Abs(value_type v) { return (value_type)Round(fabs((double)v)); }
|
||||||
|
value_type QmuParserInt::Sign(value_type v) { return (Round(v)<0) ? -1 : (Round(v)>0) ? 1 : 0; }
|
||||||
|
value_type QmuParserInt::Ite(value_type v1,
|
||||||
|
value_type v2,
|
||||||
|
value_type v3) { return (Round(v1)==1) ? Round(v2) : Round(v3); }
|
||||||
|
value_type QmuParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); }
|
||||||
|
value_type QmuParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); }
|
||||||
|
value_type QmuParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); }
|
||||||
|
value_type QmuParserInt::Div(value_type v1, value_type v2) { return Round(v1) / Round(v2); }
|
||||||
|
value_type QmuParserInt::Mod(value_type v1, value_type v2) { return Round(v1) % Round(v2); }
|
||||||
|
value_type QmuParserInt::Shr(value_type v1, value_type v2) { return Round(v1) >> Round(v2); }
|
||||||
|
value_type QmuParserInt::Shl(value_type v1, value_type v2) { return Round(v1) << Round(v2); }
|
||||||
|
value_type QmuParserInt::LogAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); }
|
||||||
|
value_type QmuParserInt::LogOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); }
|
||||||
|
value_type QmuParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); }
|
||||||
|
value_type QmuParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); }
|
||||||
|
value_type QmuParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); }
|
||||||
|
value_type QmuParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); }
|
||||||
|
value_type QmuParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); }
|
||||||
|
value_type QmuParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); }
|
||||||
|
value_type QmuParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); }
|
||||||
|
value_type QmuParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); }
|
||||||
|
value_type QmuParserInt::Not(value_type v) { return !Round(v); }
|
||||||
|
|
||||||
|
value_type QmuParserInt::Pow(value_type v1, value_type v2)
|
||||||
|
{
|
||||||
|
return std::pow((double)Round(v1), (double)Round(v2));
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Unary operator Callbacks: Infix operators
|
||||||
|
value_type QmuParserInt::UnaryMinus(value_type v)
|
||||||
|
{
|
||||||
|
return -Round(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
value_type QmuParserInt::Sum(const value_type* a_afArg, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (!a_iArgc)
|
||||||
|
throw QmuParserError(_T("too few arguments for function sum."));
|
||||||
|
|
||||||
|
value_type fRes=0;
|
||||||
|
for (int i=0; i<a_iArgc; ++i)
|
||||||
|
fRes += a_afArg[i];
|
||||||
|
|
||||||
|
return fRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
value_type QmuParserInt::Min(const value_type* a_afArg, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (!a_iArgc)
|
||||||
|
throw QmuParserError( _T("too few arguments for function min.") );
|
||||||
|
|
||||||
|
value_type fRes=a_afArg[0];
|
||||||
|
for (int i=0; i<a_iArgc; ++i)
|
||||||
|
fRes = std::min(fRes, a_afArg[i]);
|
||||||
|
|
||||||
|
return fRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
value_type QmuParserInt::Max(const value_type* a_afArg, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (!a_iArgc)
|
||||||
|
throw QmuParserError(_T("too few arguments for function min."));
|
||||||
|
|
||||||
|
value_type 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, value_type *a_fVal)
|
||||||
|
{
|
||||||
|
string_type buf(a_szExpr);
|
||||||
|
std::size_t pos = buf.find_first_not_of(_T("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 = (value_type)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, value_type *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 = (value_type)iVal;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int QmuParserInt::IsBinVal(const char_type *a_szExpr, int *a_iPos, value_type *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(_T("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( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") );
|
||||||
|
DefineOprtChars( _T("+-*^/?<>=!%&|~'_") );
|
||||||
|
DefineInfixOprtChars( _T("/+-*^?<>=!%&|~'_") );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Initialize the default functions. */
|
||||||
|
void QmuParserInt::InitFun()
|
||||||
|
{
|
||||||
|
DefineFun( _T("sign"), Sign);
|
||||||
|
DefineFun( _T("abs"), Abs);
|
||||||
|
DefineFun( _T("if"), Ite);
|
||||||
|
DefineFun( _T("sum"), Sum);
|
||||||
|
DefineFun( _T("min"), Min);
|
||||||
|
DefineFun( _T("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( _T("-"), UnaryMinus);
|
||||||
|
DefineInfixOprt( _T("!"), Not);
|
||||||
|
|
||||||
|
DefineOprt( _T("&"), LogAnd, prLOGIC);
|
||||||
|
DefineOprt( _T("|"), LogOr, prLOGIC);
|
||||||
|
DefineOprt( _T("&&"), And, prLOGIC);
|
||||||
|
DefineOprt( _T("||"), Or, prLOGIC);
|
||||||
|
|
||||||
|
DefineOprt( _T("<"), Less, prCMP);
|
||||||
|
DefineOprt( _T(">"), Greater, prCMP);
|
||||||
|
DefineOprt( _T("<="), LessEq, prCMP);
|
||||||
|
DefineOprt( _T(">="), GreaterEq, prCMP);
|
||||||
|
DefineOprt( _T("=="), Equal, prCMP);
|
||||||
|
DefineOprt( _T("!="), NotEqual, prCMP);
|
||||||
|
|
||||||
|
DefineOprt( _T("+"), Add, prADD_SUB);
|
||||||
|
DefineOprt( _T("-"), Sub, prADD_SUB);
|
||||||
|
|
||||||
|
DefineOprt( _T("*"), Mul, prMUL_DIV);
|
||||||
|
DefineOprt( _T("/"), Div, prMUL_DIV);
|
||||||
|
DefineOprt( _T("%"), Mod, prMUL_DIV);
|
||||||
|
|
||||||
|
DefineOprt( _T("^"), Pow, prPOW, oaRIGHT);
|
||||||
|
DefineOprt( _T(">>"), Shr, prMUL_DIV+1);
|
||||||
|
DefineOprt( _T("<<"), Shl, prMUL_DIV+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace qmu
|
132
src/libs/qmuparser/qmuparserint.h
Normal file
132
src/libs/qmuparser/qmuparserint.h
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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(value_type v) { return (int)(v + ((v>=0) ? 0.5 : -0.5) ); };
|
||||||
|
|
||||||
|
static value_type Abs(value_type);
|
||||||
|
static value_type Sign(value_type);
|
||||||
|
static value_type Ite(value_type, value_type, value_type);
|
||||||
|
// !! The unary Minus is a MUST, otherwise you cant use negative signs !!
|
||||||
|
static value_type UnaryMinus(value_type);
|
||||||
|
// Functions with variable number of arguments
|
||||||
|
static value_type Sum(const value_type* a_afArg, int a_iArgc); // sum
|
||||||
|
static value_type Min(const value_type* a_afArg, int a_iArgc); // minimum
|
||||||
|
static value_type Max(const value_type* a_afArg, int a_iArgc); // maximum
|
||||||
|
// binary operator callbacks
|
||||||
|
static value_type Add(value_type v1, value_type v2);
|
||||||
|
static value_type Sub(value_type v1, value_type v2);
|
||||||
|
static value_type Mul(value_type v1, value_type v2);
|
||||||
|
static value_type Div(value_type v1, value_type v2);
|
||||||
|
static value_type Mod(value_type v1, value_type v2);
|
||||||
|
static value_type Pow(value_type v1, value_type v2);
|
||||||
|
static value_type Shr(value_type v1, value_type v2);
|
||||||
|
static value_type Shl(value_type v1, value_type v2);
|
||||||
|
static value_type LogAnd(value_type v1, value_type v2);
|
||||||
|
static value_type LogOr(value_type v1, value_type v2);
|
||||||
|
static value_type And(value_type v1, value_type v2);
|
||||||
|
static value_type Or(value_type v1, value_type v2);
|
||||||
|
static value_type Xor(value_type v1, value_type v2);
|
||||||
|
static value_type Less(value_type v1, value_type v2);
|
||||||
|
static value_type Greater(value_type v1, value_type v2);
|
||||||
|
static value_type LessEq(value_type v1, value_type v2);
|
||||||
|
static value_type GreaterEq(value_type v1, value_type v2);
|
||||||
|
static value_type Equal(value_type v1, value_type v2);
|
||||||
|
static value_type NotEqual(value_type v1, value_type v2);
|
||||||
|
static value_type Not(value_type v1);
|
||||||
|
|
||||||
|
static int IsHexVal(const char_type* a_szExpr, int *a_iPos, value_type *a_iVal);
|
||||||
|
static int IsBinVal(const char_type* a_szExpr, int *a_iPos, value_type *a_iVal);
|
||||||
|
static int IsVal (const char_type* a_szExpr, int *a_iPos, value_type *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
|
||||||
|
|
122
src/libs/qmuparser/qmuparserstack.h
Normal file
122
src/libs/qmuparser/qmuparserstack.h
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPARSERSTACK_H
|
||||||
|
#define QMUPARSERSTACK_H
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <string>
|
||||||
|
#include <stack>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "qmuparsererror.h"
|
||||||
|
#include "qmuparsertoken.h"
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief This file defines the stack used by muparser.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Parser stack implementation.
|
||||||
|
|
||||||
|
Stack implementation based on a std::stack. The behaviour of pop() had been
|
||||||
|
slightly changed in order to get an error code if the stack is empty.
|
||||||
|
The stack is used within the Parser both as a value stack and as an operator stack.
|
||||||
|
|
||||||
|
\author (C) 2004-2011 Ingo Berg
|
||||||
|
*/
|
||||||
|
template <typename TValueType>
|
||||||
|
class QmuParserStack
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** \brief Type of the underlying stack implementation. */
|
||||||
|
typedef std::stack<TValueType, std::vector<TValueType> > impl_type;
|
||||||
|
|
||||||
|
impl_type m_Stack; ///< This is the actual stack.
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
QmuParserStack()
|
||||||
|
:m_Stack()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
virtual ~QmuParserStack()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Pop a value from the stack.
|
||||||
|
|
||||||
|
Unlike the standard implementation this function will return the value that
|
||||||
|
is going to be taken from the stack.
|
||||||
|
|
||||||
|
\throw ParserException in case the stack is empty.
|
||||||
|
\sa pop(int &a_iErrc)
|
||||||
|
*/
|
||||||
|
TValueType pop()
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
throw QmuParserError( _T("stack is empty.") );
|
||||||
|
|
||||||
|
TValueType el = top();
|
||||||
|
m_Stack.pop();
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Push an object into the stack.
|
||||||
|
|
||||||
|
\param a_Val object to push into the stack.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
void push(const TValueType& a_Val)
|
||||||
|
{
|
||||||
|
m_Stack.push(a_Val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Return the number of stored elements. */
|
||||||
|
unsigned size() const
|
||||||
|
{
|
||||||
|
return (unsigned)m_Stack.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Returns true if stack is empty false otherwise. */
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return m_Stack.size()==0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Return reference to the top object in the stack.
|
||||||
|
|
||||||
|
The top object is the one pushed most recently.
|
||||||
|
*/
|
||||||
|
TValueType& top()
|
||||||
|
{
|
||||||
|
return m_Stack.top();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace MathUtils
|
||||||
|
|
||||||
|
#endif
|
150
src/libs/qmuparser/qmuparsertemplatemagic.h
Normal file
150
src/libs/qmuparser/qmuparsertemplatemagic.h
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
#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(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Cos(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Tan(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE ASin(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE ACos(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE ATan(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE ATan2(TYPE, TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Sinh(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Cosh(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Tanh(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE ASinh(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE ACosh(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE ATanh(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Log(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Log2(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Log10(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Exp(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Abs(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Sqrt(TYPE) { throw QmuParserError(_T("unimplemented function.")); } \
|
||||||
|
static TYPE Rint(TYPE) { throw QmuParserError(_T("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
|
1447
src/libs/qmuparser/qmuparsertest.cpp
Normal file
1447
src/libs/qmuparser/qmuparsertest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
207
src/libs/qmuparser/qmuparsertest.h
Normal file
207
src/libs/qmuparser/qmuparsertest.h
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPARSERTEST_H
|
||||||
|
#define QMUPARSERTEST_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <numeric> // for accumulate
|
||||||
|
#include "qmuparser.h"
|
||||||
|
#include "qmuparserint.h"
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief This file contains the parser test class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
/** \brief Namespace for test cases. */
|
||||||
|
namespace Test
|
||||||
|
{
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Test cases for unit testing.
|
||||||
|
|
||||||
|
(C) 2004-2011 Ingo Berg
|
||||||
|
*/
|
||||||
|
class QmuParserTester // final
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static int c_iCount;
|
||||||
|
|
||||||
|
// Multiarg callbacks
|
||||||
|
static value_type f1of1(value_type v) { return v;};
|
||||||
|
|
||||||
|
static value_type f1of2(value_type v, value_type ) {return v;};
|
||||||
|
static value_type f2of2(value_type , value_type v) {return v;};
|
||||||
|
|
||||||
|
static value_type f1of3(value_type v, value_type , value_type ) {return v;};
|
||||||
|
static value_type f2of3(value_type , value_type v, value_type ) {return v;};
|
||||||
|
static value_type f3of3(value_type , value_type , value_type v) {return v;};
|
||||||
|
|
||||||
|
static value_type f1of4(value_type v, value_type, value_type , value_type ) {return v;}
|
||||||
|
static value_type f2of4(value_type , value_type v, value_type , value_type ) {return v;}
|
||||||
|
static value_type f3of4(value_type , value_type, value_type v, value_type ) {return v;}
|
||||||
|
static value_type f4of4(value_type , value_type, value_type , value_type v) {return v;}
|
||||||
|
|
||||||
|
static value_type f1of5(value_type v, value_type, value_type , value_type , value_type ) { return v; }
|
||||||
|
static value_type f2of5(value_type , value_type v, value_type , value_type , value_type ) { return v; }
|
||||||
|
static value_type f3of5(value_type , value_type, value_type v, value_type , value_type ) { return v; }
|
||||||
|
static value_type f4of5(value_type , value_type, value_type , value_type v, value_type ) { return v; }
|
||||||
|
static value_type f5of5(value_type , value_type, value_type , value_type , value_type v) { return v; }
|
||||||
|
|
||||||
|
static value_type Min(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1<a_fVal2) ? a_fVal1 : a_fVal2; }
|
||||||
|
static value_type Max(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1>a_fVal2) ? a_fVal1 : a_fVal2; }
|
||||||
|
|
||||||
|
static value_type plus2(value_type v1) { return v1+2; }
|
||||||
|
static value_type times3(value_type v1) { return v1*3; }
|
||||||
|
static value_type sqr(value_type v1) { return v1*v1; }
|
||||||
|
static value_type sign(value_type v) { return -v; }
|
||||||
|
static value_type add(value_type v1, value_type v2) { return v1+v2; }
|
||||||
|
static value_type land(value_type v1, value_type v2) { return (int)v1 & (int)v2; }
|
||||||
|
|
||||||
|
|
||||||
|
static value_type FirstArg(const value_type* a_afArg, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (!a_iArgc)
|
||||||
|
throw qmu::QmuParser::exception_type( _T("too few arguments for function FirstArg.") );
|
||||||
|
|
||||||
|
return a_afArg[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type LastArg(const value_type* a_afArg, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (!a_iArgc)
|
||||||
|
throw qmu::QmuParser::exception_type( _T("too few arguments for function LastArg.") );
|
||||||
|
|
||||||
|
return a_afArg[a_iArgc-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type Sum(const value_type* a_afArg, int a_iArgc)
|
||||||
|
{
|
||||||
|
if (!a_iArgc)
|
||||||
|
throw qmu::QmuParser::exception_type( _T("too few arguments for function sum.") );
|
||||||
|
|
||||||
|
value_type fRes=0;
|
||||||
|
for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];
|
||||||
|
return fRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type Rnd(value_type v)
|
||||||
|
{
|
||||||
|
return (value_type)(1+(v*std::rand()/(RAND_MAX+1.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type RndWithString(const char_type*)
|
||||||
|
{
|
||||||
|
return (value_type)( 1 + (1000.0f * std::rand() / (RAND_MAX + 1.0) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type Ping()
|
||||||
|
{
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type ValueOf(const char_type*)
|
||||||
|
{
|
||||||
|
return 123;
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type StrFun1(const char_type* v1)
|
||||||
|
{
|
||||||
|
int val(0);
|
||||||
|
stringstream_type(v1) >> val;
|
||||||
|
return (value_type)val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type StrFun2(const char_type* v1, value_type v2)
|
||||||
|
{
|
||||||
|
int val(0);
|
||||||
|
stringstream_type(v1) >> val;
|
||||||
|
return (value_type)(val + v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type StrFun3(const char_type* v1, value_type v2, value_type v3)
|
||||||
|
{
|
||||||
|
int val(0);
|
||||||
|
stringstream_type(v1) >> val;
|
||||||
|
return val + v2 + v3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type StrToFloat(const char_type* a_szMsg)
|
||||||
|
{
|
||||||
|
value_type val(0);
|
||||||
|
stringstream_type(a_szMsg) >> val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// postfix operator callback
|
||||||
|
static value_type Mega(value_type a_fVal) { return a_fVal * (value_type)1e6; }
|
||||||
|
static value_type Micro(value_type a_fVal) { return a_fVal * (value_type)1e-6; }
|
||||||
|
static value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
|
||||||
|
|
||||||
|
// Custom value recognition
|
||||||
|
static int IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal);
|
||||||
|
|
||||||
|
int TestNames();
|
||||||
|
int TestSyntax();
|
||||||
|
int TestMultiArg();
|
||||||
|
int TestPostFix();
|
||||||
|
int TestExpression();
|
||||||
|
int TestInfixOprt();
|
||||||
|
int TestBinOprt();
|
||||||
|
int TestVarConst();
|
||||||
|
int TestInterface();
|
||||||
|
int TestException();
|
||||||
|
int TestStrArg();
|
||||||
|
int TestIfThenElse();
|
||||||
|
|
||||||
|
void Abort() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef int (QmuParserTester::*testfun_type)();
|
||||||
|
|
||||||
|
QmuParserTester();
|
||||||
|
void Run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<testfun_type> m_vTestFun;
|
||||||
|
void AddTest(testfun_type a_pFun);
|
||||||
|
|
||||||
|
// Test Double Parser
|
||||||
|
int EqnTest(const string_type& a_str, double a_fRes, bool a_fPass);
|
||||||
|
int EqnTestWithVarChange(const string_type& a_str,
|
||||||
|
double a_fRes1,
|
||||||
|
double a_fVar1,
|
||||||
|
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
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
396
src/libs/qmuparser/qmuparsertoken.h
Normal file
396
src/libs/qmuparser/qmuparsertoken.h
Normal file
|
@ -0,0 +1,396 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPARSERTOKEN_H
|
||||||
|
#define QMUPARSERTOKEN_H
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <string>
|
||||||
|
#include <stack>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "qmuparsererror.h"
|
||||||
|
#include "qmuparsercallback.h"
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief This file contains the parser token definition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
/** \brief Encapsulation of the data for a single formula token.
|
||||||
|
|
||||||
|
Formula token implementation. Part of the Math Parser Package.
|
||||||
|
Formula tokens can be either one of the following:
|
||||||
|
<ul>
|
||||||
|
<li>value</li>
|
||||||
|
<li>variable</li>
|
||||||
|
<li>function with numerical arguments</li>
|
||||||
|
<li>functions with a string as argument</li>
|
||||||
|
<li>prefix operators</li>
|
||||||
|
<li>infix operators</li>
|
||||||
|
<li>binary operator</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
\author (C) 2004-2013 Ingo Berg
|
||||||
|
*/
|
||||||
|
template<typename TBase, typename TString>
|
||||||
|
class QmuParserToken
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode.
|
||||||
|
ETypeCode m_iType;
|
||||||
|
void *m_pTok; ///< Stores Token pointer; not applicable for all tokens
|
||||||
|
int m_iIdx; ///< An otional index to an external buffer storing the token data
|
||||||
|
TString m_strTok; ///< Token string
|
||||||
|
TString m_strVal; ///< Value for string variables
|
||||||
|
value_type m_fVal; ///< the value
|
||||||
|
std::auto_ptr<QmuParserCallback> m_pCallback;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Constructor (default).
|
||||||
|
|
||||||
|
Sets token to an neutral state of type cmUNKNOWN.
|
||||||
|
\throw nothrow
|
||||||
|
\sa ECmdCode
|
||||||
|
*/
|
||||||
|
QmuParserToken()
|
||||||
|
:m_iCode(cmUNKNOWN)
|
||||||
|
,m_iType(tpVOID)
|
||||||
|
,m_pTok(0)
|
||||||
|
,m_iIdx(-1)
|
||||||
|
,m_strTok()
|
||||||
|
,m_pCallback()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Create token from another one.
|
||||||
|
|
||||||
|
Implemented by calling Assign(...)
|
||||||
|
\throw nothrow
|
||||||
|
\post m_iType==cmUNKNOWN
|
||||||
|
\sa #Assign
|
||||||
|
*/
|
||||||
|
QmuParserToken(const QmuParserToken &a_Tok)
|
||||||
|
{
|
||||||
|
Assign(a_Tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Assignement operator.
|
||||||
|
|
||||||
|
Copy token state from another token and return this.
|
||||||
|
Implemented by calling Assign(...).
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
QmuParserToken& operator=(const QmuParserToken &a_Tok)
|
||||||
|
{
|
||||||
|
Assign(a_Tok);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Copy token information from argument.
|
||||||
|
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
void Assign(const QmuParserToken &a_Tok)
|
||||||
|
{
|
||||||
|
m_iCode = a_Tok.m_iCode;
|
||||||
|
m_pTok = a_Tok.m_pTok;
|
||||||
|
m_strTok = a_Tok.m_strTok;
|
||||||
|
m_iIdx = a_Tok.m_iIdx;
|
||||||
|
m_strVal = a_Tok.m_strVal;
|
||||||
|
m_iType = a_Tok.m_iType;
|
||||||
|
m_fVal = a_Tok.m_fVal;
|
||||||
|
// create new callback object if a_Tok has one
|
||||||
|
m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Assign a token type.
|
||||||
|
|
||||||
|
Token may not be of type value, variable or function. Those have seperate set functions.
|
||||||
|
|
||||||
|
\pre [assert] a_iType!=cmVAR
|
||||||
|
\pre [assert] a_iType!=cmVAL
|
||||||
|
\pre [assert] a_iType!=cmFUNC
|
||||||
|
\post m_fVal = 0
|
||||||
|
\post m_pTok = 0
|
||||||
|
*/
|
||||||
|
QmuParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString())
|
||||||
|
{
|
||||||
|
// The following types cant be set this way, they have special Set functions
|
||||||
|
assert(a_iType!=cmVAR);
|
||||||
|
assert(a_iType!=cmVAL);
|
||||||
|
assert(a_iType!=cmFUNC);
|
||||||
|
|
||||||
|
m_iCode = a_iType;
|
||||||
|
m_iType = tpVOID;
|
||||||
|
m_pTok = 0;
|
||||||
|
m_strTok = a_strTok;
|
||||||
|
m_iIdx = -1;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Set Callback type. */
|
||||||
|
QmuParserToken& Set(const QmuParserCallback &a_pCallback, const TString &a_sTok)
|
||||||
|
{
|
||||||
|
assert(a_pCallback.GetAddr());
|
||||||
|
|
||||||
|
m_iCode = a_pCallback.GetCode();
|
||||||
|
m_iType = tpVOID;
|
||||||
|
m_strTok = a_sTok;
|
||||||
|
m_pCallback.reset(new QmuParserCallback(a_pCallback));
|
||||||
|
|
||||||
|
m_pTok = 0;
|
||||||
|
m_iIdx = -1;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Make this token a value token.
|
||||||
|
|
||||||
|
Member variables not necessary for value tokens will be invalidated.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
QmuParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString())
|
||||||
|
{
|
||||||
|
m_iCode = cmVAL;
|
||||||
|
m_iType = tpDBL;
|
||||||
|
m_fVal = a_fVal;
|
||||||
|
m_strTok = a_strTok;
|
||||||
|
m_iIdx = -1;
|
||||||
|
|
||||||
|
m_pTok = 0;
|
||||||
|
m_pCallback.reset(0);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief make this token a variable token.
|
||||||
|
|
||||||
|
Member variables not necessary for variable tokens will be invalidated.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
QmuParserToken& SetVar(TBase *a_pVar, const TString &a_strTok)
|
||||||
|
{
|
||||||
|
m_iCode = cmVAR;
|
||||||
|
m_iType = tpDBL;
|
||||||
|
m_strTok = a_strTok;
|
||||||
|
m_iIdx = -1;
|
||||||
|
m_pTok = (void*)a_pVar;
|
||||||
|
m_pCallback.reset(0);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Make this token a variable token.
|
||||||
|
|
||||||
|
Member variables not necessary for variable tokens will be invalidated.
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
QmuParserToken& SetString(const TString &a_strTok, std::size_t a_iSize)
|
||||||
|
{
|
||||||
|
m_iCode = cmSTRING;
|
||||||
|
m_iType = tpSTR;
|
||||||
|
m_strTok = a_strTok;
|
||||||
|
m_iIdx = static_cast<int>(a_iSize);
|
||||||
|
|
||||||
|
m_pTok = 0;
|
||||||
|
m_pCallback.reset(0);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Set an index associated with the token related data.
|
||||||
|
|
||||||
|
In cmSTRFUNC - This is the index to a string table in the main parser.
|
||||||
|
\param a_iIdx The index the string function result will take in the bytecode parser.
|
||||||
|
\throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING
|
||||||
|
*/
|
||||||
|
void SetIdx(int a_iIdx)
|
||||||
|
{
|
||||||
|
if (m_iCode!=cmSTRING || a_iIdx<0)
|
||||||
|
throw QmuParserError(ecINTERNAL_ERROR);
|
||||||
|
|
||||||
|
m_iIdx = a_iIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Return Index associated with the token related data.
|
||||||
|
|
||||||
|
In cmSTRFUNC - This is the index to a string table in the main parser.
|
||||||
|
|
||||||
|
\throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING
|
||||||
|
\return The index the result will take in the Bytecode calculatin array (#m_iIdx).
|
||||||
|
*/
|
||||||
|
int GetIdx() const
|
||||||
|
{
|
||||||
|
if (m_iIdx<0 || m_iCode!=cmSTRING )
|
||||||
|
throw QmuParserError(ecINTERNAL_ERROR);
|
||||||
|
|
||||||
|
return m_iIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Return the token type.
|
||||||
|
|
||||||
|
\return #m_iType
|
||||||
|
\throw nothrow
|
||||||
|
*/
|
||||||
|
ECmdCode GetCode() const
|
||||||
|
{
|
||||||
|
if (m_pCallback.get())
|
||||||
|
{
|
||||||
|
return m_pCallback->GetCode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return m_iCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
ETypeCode GetType() const
|
||||||
|
{
|
||||||
|
if (m_pCallback.get())
|
||||||
|
{
|
||||||
|
return m_pCallback->GetType();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return m_iType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int GetPri() const
|
||||||
|
{
|
||||||
|
if ( !m_pCallback.get())
|
||||||
|
throw QmuParserError(ecINTERNAL_ERROR);
|
||||||
|
|
||||||
|
if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX)
|
||||||
|
throw QmuParserError(ecINTERNAL_ERROR);
|
||||||
|
|
||||||
|
return m_pCallback->GetPri();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
EOprtAssociativity GetAssociativity() const
|
||||||
|
{
|
||||||
|
if (m_pCallback.get()==NULL || m_pCallback->GetCode()!=cmOPRT_BIN)
|
||||||
|
throw QmuParserError(ecINTERNAL_ERROR);
|
||||||
|
|
||||||
|
return m_pCallback->GetAssociativity();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Return the address of the callback function assoziated with
|
||||||
|
function and operator tokens.
|
||||||
|
|
||||||
|
\return The pointer stored in #m_pTok.
|
||||||
|
\throw exception_type if token type is non of:
|
||||||
|
<ul>
|
||||||
|
<li>cmFUNC</li>
|
||||||
|
<li>cmSTRFUNC</li>
|
||||||
|
<li>cmPOSTOP</li>
|
||||||
|
<li>cmINFIXOP</li>
|
||||||
|
<li>cmOPRT_BIN</li>
|
||||||
|
</ul>
|
||||||
|
\sa ECmdCode
|
||||||
|
*/
|
||||||
|
generic_fun_type GetFuncAddr() const
|
||||||
|
{
|
||||||
|
return (m_pCallback.get()) ? (generic_fun_type)m_pCallback->GetAddr() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \biref Get value of the token.
|
||||||
|
|
||||||
|
Only applicable to variable and value tokens.
|
||||||
|
\throw exception_type if token is no value/variable token.
|
||||||
|
*/
|
||||||
|
TBase GetVal() const
|
||||||
|
{
|
||||||
|
switch (m_iCode)
|
||||||
|
{
|
||||||
|
case cmVAL: return m_fVal;
|
||||||
|
case cmVAR: return *((TBase*)m_pTok);
|
||||||
|
default: throw QmuParserError(ecVAL_EXPECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Get address of a variable token.
|
||||||
|
|
||||||
|
Valid only if m_iType==CmdVar.
|
||||||
|
\throw exception_type if token is no variable token.
|
||||||
|
*/
|
||||||
|
TBase* GetVar() const
|
||||||
|
{
|
||||||
|
if (m_iCode!=cmVAR)
|
||||||
|
throw QmuParserError(ecINTERNAL_ERROR);
|
||||||
|
|
||||||
|
return (TBase*)m_pTok;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Return the number of function arguments.
|
||||||
|
|
||||||
|
Valid only if m_iType==CmdFUNC.
|
||||||
|
*/
|
||||||
|
int GetArgCount() const
|
||||||
|
{
|
||||||
|
assert(m_pCallback.get());
|
||||||
|
|
||||||
|
if (!m_pCallback->GetAddr())
|
||||||
|
throw QmuParserError(ecINTERNAL_ERROR);
|
||||||
|
|
||||||
|
return m_pCallback->GetArgc();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \brief Return the token identifier.
|
||||||
|
|
||||||
|
If #m_iType is cmSTRING the token identifier is the value of the string argument
|
||||||
|
for a string function.
|
||||||
|
\return #m_strTok
|
||||||
|
\throw nothrow
|
||||||
|
\sa m_strTok
|
||||||
|
*/
|
||||||
|
const TString& GetAsString() const
|
||||||
|
{
|
||||||
|
return m_strTok;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace qmu
|
||||||
|
|
||||||
|
#endif
|
953
src/libs/qmuparser/qmuparsertokenreader.cpp
Normal file
953
src/libs/qmuparser/qmuparsertokenreader.cpp
Normal file
|
@ -0,0 +1,953 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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>
|
||||||
|
|
||||||
|
#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
|
||||||
|
*/
|
||||||
|
const string_type& QmuParserTokenReader::GetExpr() const
|
||||||
|
{
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
void QmuParserTokenReader::SetFormula(const string_type &a_strFormula)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
std::stack<int> FunArgs;
|
||||||
|
const char_type *szFormula = m_strFormula.c_str();
|
||||||
|
token_type tok;
|
||||||
|
|
||||||
|
// Ignore all non printable characters when reading the expression
|
||||||
|
while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20)
|
||||||
|
++m_iPos;
|
||||||
|
|
||||||
|
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.)
|
||||||
|
if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) )
|
||||||
|
return SaveBeforeReturn(tok);
|
||||||
|
|
||||||
|
// Check for unknown token
|
||||||
|
//
|
||||||
|
// !!! From this point on there is no exit without an exception possible...
|
||||||
|
//
|
||||||
|
string_type strTok;
|
||||||
|
int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
|
||||||
|
if (iEnd!=m_iPos)
|
||||||
|
Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok);
|
||||||
|
|
||||||
|
Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \brief Extract all characters that belong to a certain charset.
|
||||||
|
|
||||||
|
\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 char_type *a_szCharSet,
|
||||||
|
string_type &a_sTok,
|
||||||
|
int a_iPos) const
|
||||||
|
{
|
||||||
|
int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos);
|
||||||
|
|
||||||
|
if (iEnd==(int)string_type::npos)
|
||||||
|
iEnd = (int)m_strFormula.length();
|
||||||
|
|
||||||
|
// Assign token string if there was something found
|
||||||
|
if (a_iPos!=iEnd)
|
||||||
|
a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd);
|
||||||
|
|
||||||
|
return iEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \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(string_type &a_sTok,
|
||||||
|
int a_iPos) const
|
||||||
|
{
|
||||||
|
int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidInfixOprtChars(), a_iPos);
|
||||||
|
if (iEnd==(int)string_type::npos)
|
||||||
|
iEnd = (int)m_strFormula.length();
|
||||||
|
|
||||||
|
// Assign token string if there was something found
|
||||||
|
if (a_iPos!=iEnd)
|
||||||
|
{
|
||||||
|
a_sTok = string_type( m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd);
|
||||||
|
return iEnd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/** \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)
|
||||||
|
{
|
||||||
|
const char_type **const pOprtDef = m_pParser->GetOprtDef(),
|
||||||
|
*const szFormula = m_strFormula.c_str();
|
||||||
|
|
||||||
|
// Compare token with function and operator strings
|
||||||
|
// check string for operator/function
|
||||||
|
for (int i=0; pOprtDef[i]; i++)
|
||||||
|
{
|
||||||
|
std::size_t len( std::char_traits<char_type>::length(pOprtDef[i]) );
|
||||||
|
if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) )
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
|
||||||
|
|
||||||
|
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)
|
||||||
|
Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
|
||||||
|
|
||||||
|
m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN;
|
||||||
|
|
||||||
|
if (--m_iBrackets<0)
|
||||||
|
Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmELSE:
|
||||||
|
if (m_iSynFlags & noELSE)
|
||||||
|
Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);
|
||||||
|
|
||||||
|
m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cmIF:
|
||||||
|
if (m_iSynFlags & noIF)
|
||||||
|
Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
m_iPos += (int)len;
|
||||||
|
a_Tok.Set( (ECmdCode)i, pOprtDef[i] );
|
||||||
|
return true;
|
||||||
|
} // if operator string found
|
||||||
|
} // end of for all operator strings
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
bool QmuParserTokenReader::IsArgSep(token_type &a_Tok)
|
||||||
|
{
|
||||||
|
const char_type* szFormula = m_strFormula.c_str();
|
||||||
|
|
||||||
|
if (szFormula[m_iPos]==m_cArgSep)
|
||||||
|
{
|
||||||
|
// copy the separator into null terminated string
|
||||||
|
char_type szSep[2];
|
||||||
|
szSep[0] = m_cArgSep;
|
||||||
|
szSep[1] = 0;
|
||||||
|
|
||||||
|
if (m_iSynFlags & noARG_SEP)
|
||||||
|
Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
const char_type* szFormula = m_strFormula.c_str();
|
||||||
|
|
||||||
|
// check for EOF
|
||||||
|
if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/)
|
||||||
|
{
|
||||||
|
if ( m_iSynFlags & noEND )
|
||||||
|
Error(ecUNEXPECTED_EOF, m_iPos);
|
||||||
|
|
||||||
|
if (m_iBrackets>0)
|
||||||
|
Error(ecMISSING_PARENS, m_iPos, _T(")"));
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
string_type sTok;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (sTok.find(it->first)!=0)
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
string_type strTok;
|
||||||
|
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
|
||||||
|
const char_type *szFormula = m_strFormula.c_str();
|
||||||
|
if (szFormula[iEnd]!='(')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
a_Tok.Set(item->second, strTok);
|
||||||
|
|
||||||
|
m_iPos = (int)iEnd;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
const char_type *const szExpr = m_strFormula.c_str();
|
||||||
|
string_type strTok;
|
||||||
|
|
||||||
|
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
|
||||||
|
const char_type **const pOprtDef = m_pParser->GetOprtDef();
|
||||||
|
for (int i=0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i)
|
||||||
|
{
|
||||||
|
if (string_type(pOprtDef[i])==strTok)
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
const string_type &sID = it->first;
|
||||||
|
if ( sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()) )
|
||||||
|
{
|
||||||
|
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
|
||||||
|
string_type sTok;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (sTok.find(it->first)!=0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
a_Tok.Set(it->second, sTok);
|
||||||
|
m_iPos += (int)it->first.length();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
string_type strTok;
|
||||||
|
value_type fVal(0);
|
||||||
|
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)
|
||||||
|
Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
|
||||||
|
|
||||||
|
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;
|
||||||
|
if ( (*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal)==1 )
|
||||||
|
{
|
||||||
|
strTok.assign(m_strFormula.c_str(), iStart, m_iPos);
|
||||||
|
if (m_iSynFlags & noVAL)
|
||||||
|
Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
string_type strTok;
|
||||||
|
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;
|
||||||
|
|
||||||
|
string_type strTok;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
string_type strTok;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData);
|
||||||
|
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
|
||||||
|
{
|
||||||
|
a_Tok.SetVar((value_type*)&m_fZero, strTok);
|
||||||
|
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;
|
||||||
|
|
||||||
|
string_type strBuf(&m_strFormula[m_iPos+1]);
|
||||||
|
std::size_t iEnd(0), iSkip(0);
|
||||||
|
|
||||||
|
// parser over escaped '\"' end replace them with '"'
|
||||||
|
for(iEnd=(int)strBuf.find( _T("\"") ); iEnd!=0 && iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T("\""), iEnd))
|
||||||
|
{
|
||||||
|
if (strBuf[iEnd-1]!='\\') break;
|
||||||
|
strBuf.replace(iEnd-1, 2, _T("\"") );
|
||||||
|
iSkip++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iEnd==string_type::npos)
|
||||||
|
Error(ecUNTERMINATED_STRING, m_iPos, _T("\"") );
|
||||||
|
|
||||||
|
string_type strTok(strBuf.begin(), strBuf.begin()+iEnd);
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 wg Anfhrungszeichen; +iSkip fr entfernte escape zeichen
|
||||||
|
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,
|
||||||
|
const string_type &a_sTok) const
|
||||||
|
{
|
||||||
|
m_pParser->Error(a_iErrc, a_iPos, a_sTok);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void QmuParserTokenReader::SetArgSep(char_type cArgSep)
|
||||||
|
{
|
||||||
|
m_cArgSep = cArgSep;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
char_type QmuParserTokenReader::GetArgSep() const
|
||||||
|
{
|
||||||
|
return m_cArgSep;
|
||||||
|
}
|
||||||
|
} // namespace qmu
|
||||||
|
|
158
src/libs/qmuparser/qmuparsertokenreader.h
Normal file
158
src/libs/qmuparser/qmuparsertokenreader.h
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** 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 QMUPARSERTOKENREADER_H
|
||||||
|
#define QMUPARSERTOKENREADER_H
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <stack>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "qmuparserdef.h"
|
||||||
|
#include "qmuparsertoken.h"
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
\brief This file contains the parser token reader definition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace qmu
|
||||||
|
{
|
||||||
|
// Forward declaration
|
||||||
|
class QmuParserBase;
|
||||||
|
|
||||||
|
/** \brief Token reader for the ParserBase class.
|
||||||
|
|
||||||
|
*/
|
||||||
|
class QmuParserTokenReader
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef QmuParserToken<value_type, string_type> token_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
QmuParserTokenReader(QmuParserBase *a_pParent);
|
||||||
|
QmuParserTokenReader* Clone(QmuParserBase *a_pParent) const;
|
||||||
|
|
||||||
|
void AddValIdent(identfun_type a_pCallback);
|
||||||
|
void SetVarCreator(facfun_type a_pFactory, void *pUserData);
|
||||||
|
void SetFormula(const string_type &a_strFormula);
|
||||||
|
void SetArgSep(char_type cArgSep);
|
||||||
|
|
||||||
|
int GetPos() const;
|
||||||
|
const string_type& GetExpr() const;
|
||||||
|
varmap_type& GetUsedVar();
|
||||||
|
char_type GetArgSep() const;
|
||||||
|
|
||||||
|
void IgnoreUndefVar(bool bIgnore);
|
||||||
|
void ReInit();
|
||||||
|
token_type ReadNextToken();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** \brief Syntax codes.
|
||||||
|
|
||||||
|
The syntax codes control the syntax check done during the first time parsing of
|
||||||
|
the expression string. They are flags that indicate which tokens are allowed next
|
||||||
|
if certain tokens are identified.
|
||||||
|
*/
|
||||||
|
enum ESynCodes
|
||||||
|
{
|
||||||
|
noBO = 1 << 0, ///< to avoid i.e. "cos(7)("
|
||||||
|
noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()"
|
||||||
|
noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14"
|
||||||
|
noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a"
|
||||||
|
noARG_SEP = 1 << 4, ///< to avoid i.e. ",," or "+," ...
|
||||||
|
noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin"
|
||||||
|
noOPT = 1 << 6, ///< to avoid i.e. "(+)"
|
||||||
|
noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!"
|
||||||
|
noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4"
|
||||||
|
noEND = 1 << 9, ///< to avoid unexpected end of formula
|
||||||
|
noSTR = 1 << 10, ///< to block numeric arguments on string functions
|
||||||
|
noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7"
|
||||||
|
noIF = 1 << 12,
|
||||||
|
noELSE = 1 << 13,
|
||||||
|
sfSTART_OF_LINE = noOPT | noBC | noPOSTOP | noASSIGN | noIF | noELSE | noARG_SEP,
|
||||||
|
noANY = ~0 ///< All of he above flags set
|
||||||
|
};
|
||||||
|
|
||||||
|
QmuParserTokenReader(const QmuParserTokenReader &a_Reader);
|
||||||
|
QmuParserTokenReader& operator=(const QmuParserTokenReader &a_Reader);
|
||||||
|
void Assign(const QmuParserTokenReader &a_Reader);
|
||||||
|
|
||||||
|
void SetParent(QmuParserBase *a_pParent);
|
||||||
|
int ExtractToken(const char_type *a_szCharSet,
|
||||||
|
string_type &a_strTok,
|
||||||
|
int a_iPos) const;
|
||||||
|
int ExtractOperatorToken(string_type &a_sTok, int a_iPos) const;
|
||||||
|
|
||||||
|
bool IsBuiltIn(token_type &a_Tok);
|
||||||
|
bool IsArgSep(token_type &a_Tok);
|
||||||
|
bool IsEOF(token_type &a_Tok);
|
||||||
|
bool IsInfixOpTok(token_type &a_Tok);
|
||||||
|
bool IsFunTok(token_type &a_Tok);
|
||||||
|
bool IsPostOpTok(token_type &a_Tok);
|
||||||
|
bool IsOprt(token_type &a_Tok);
|
||||||
|
bool IsValTok(token_type &a_Tok);
|
||||||
|
bool IsVarTok(token_type &a_Tok);
|
||||||
|
bool IsStrVarTok(token_type &a_Tok);
|
||||||
|
bool IsUndefVarTok(token_type &a_Tok);
|
||||||
|
bool IsString(token_type &a_Tok);
|
||||||
|
void Error(EErrorCodes a_iErrc,
|
||||||
|
int a_iPos = -1,
|
||||||
|
const string_type &a_sTok = string_type() ) const;
|
||||||
|
|
||||||
|
token_type& SaveBeforeReturn(const token_type &tok);
|
||||||
|
|
||||||
|
QmuParserBase *m_pParser;
|
||||||
|
string_type m_strFormula;
|
||||||
|
int m_iPos;
|
||||||
|
int m_iSynFlags;
|
||||||
|
bool m_bIgnoreUndefVar;
|
||||||
|
|
||||||
|
const funmap_type *m_pFunDef;
|
||||||
|
const funmap_type *m_pPostOprtDef;
|
||||||
|
const funmap_type *m_pInfixOprtDef;
|
||||||
|
const funmap_type *m_pOprtDef;
|
||||||
|
const valmap_type *m_pConstDef;
|
||||||
|
const strmap_type *m_pStrVarDef;
|
||||||
|
varmap_type *m_pVarDef; ///< The only non const pointer to parser internals
|
||||||
|
facfun_type m_pFactory;
|
||||||
|
void *m_pFactoryData;
|
||||||
|
std::list<identfun_type> m_vIdentFun; ///< Value token identification function
|
||||||
|
varmap_type m_UsedVar;
|
||||||
|
value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables
|
||||||
|
int m_iBrackets;
|
||||||
|
token_type m_lastTok;
|
||||||
|
char_type m_cArgSep; ///< The character used for separating function arguments
|
||||||
|
};
|
||||||
|
} // namespace qmu
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
30
src/libs/qmuparser/stable.cpp
Normal file
30
src/libs/qmuparser/stable.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/************************************************************************
|
||||||
|
**
|
||||||
|
** @file stable.cpp
|
||||||
|
** @author Roman Telezhinsky <dismine@gmail.com>
|
||||||
|
** @date November 15, 2013
|
||||||
|
**
|
||||||
|
** @brief
|
||||||
|
** @copyright
|
||||||
|
** This source code is part of the Valentine project, a pattern making
|
||||||
|
** program, whose allow create and modeling patterns of clothing.
|
||||||
|
** Copyright (C) 2013 Valentina project
|
||||||
|
** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Valentina is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 3 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** Valentina is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
**
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
// Build the precompiled headers.
|
||||||
|
#include "stable.h"
|
46
src/libs/qmuparser/stable.h
Normal file
46
src/libs/qmuparser/stable.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/************************************************************************
|
||||||
|
**
|
||||||
|
** @file stable.h
|
||||||
|
** @author Roman Telezhinsky <dismine@gmail.com>
|
||||||
|
** @date November 15, 2013
|
||||||
|
**
|
||||||
|
** @brief
|
||||||
|
** @copyright
|
||||||
|
** This source code is part of the Valentine project, a pattern making
|
||||||
|
** program, whose allow create and modeling patterns of clothing.
|
||||||
|
** Copyright (C) 2013 Valentina project
|
||||||
|
** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Valentina is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 3 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** Valentina is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
**
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef STABLE_H
|
||||||
|
#define STABLE_H
|
||||||
|
|
||||||
|
/* I like to include this pragma too, so the build log indicates if pre-compiled headers were in use. */
|
||||||
|
#pragma message("Compiling precompiled headers for QmuParser library.\n")
|
||||||
|
|
||||||
|
/* Add C includes here */
|
||||||
|
|
||||||
|
#if defined __cplusplus
|
||||||
|
/* Add C++ includes here */
|
||||||
|
#ifdef Q_CC_MSVC
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#endif
|
||||||
|
#include <QtCore>
|
||||||
|
#include <QtGlobal>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // STABLE_H
|
|
@ -1,13 +1,16 @@
|
||||||
TEMPLATE = subdirs
|
TEMPLATE = subdirs
|
||||||
#SUBDIRS = sub_lib sub_tests sub_app
|
#SUBDIRS = sub_lib sub_tests sub_app
|
||||||
SUBDIRS = sub_app
|
SUBDIRS = \
|
||||||
|
sub_app \
|
||||||
|
sub_lib_qmuparser
|
||||||
|
|
||||||
#sub_lib.subdir = lib
|
sub_lib_qmuparser.subdir = libs/qmuparser
|
||||||
|
sub_lib_qmuparser.file = libs/qmuparser/qmuparser.pro
|
||||||
#sub_tests.file = tests/proj.pro
|
#sub_tests.file = tests/proj.pro
|
||||||
#sub_tests.depends = sub_lib
|
#sub_tests.depends = sub_lib
|
||||||
sub_app.subdir = app
|
sub_app.subdir = app
|
||||||
sub_app.file = app/app.pro
|
sub_app.file = app/app.pro
|
||||||
#sub_app.depends = sub_lib
|
sub_app.depends = sub_lib_qmuparser
|
||||||
|
|
||||||
#This makes it possible to use make -j 4 on your fancy quad-core system with a project that consists of several
|
#This makes it possible to use make -j 4 on your fancy quad-core system with a project that consists of several
|
||||||
#components that depend on each other. To simplify the process a bit, the following test function can be defined:
|
#components that depend on each other. To simplify the process a bit, the following test function can be defined:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user