[muparser] Parser mathematical functions to return errors instead of throw

Remove exceptions from Parser functions such as sqrt, min, and others.
This commit is contained in:
ridiculousfish
2017-11-24 23:55:51 -08:00
parent bceef6c125
commit 91c28449aa
6 changed files with 146 additions and 116 deletions

View File

@@ -102,7 +102,7 @@ class ParserBase {
int GetNumResults() const;
void SetExpr(const string_type &a_sExpr);
OptionalError SetExpr(const string_type &a_sExpr);
void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL);
void SetDecSep(char_type cDecSep);
@@ -123,14 +123,17 @@ class ParserBase {
*/
template <typename T>
void DefineFun(const string_type &a_strName, T a_pFun, bool a_bAllowOpt = true) {
AddCallback(a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars());
auto oerr =
AddCallback(a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars());
if (oerr.has_error()) throw oerr.error();
}
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);
OptionalError DefineOprt(const string_type &a_strName, fun_type2 a_pFun, unsigned a_iPri = 0,
EOprtAssociativity a_eAssociativity = oaLEFT,
bool a_bAllowOpt = false);
OptionalError DefineConst(const string_type &a_sName, value_type a_fVal);
OptionalError DefineStrConst(const string_type &a_sName, const string_type &a_strVal);
OptionalError 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);
@@ -161,8 +164,8 @@ class ParserBase {
void SetArgSep(char_type cArgSep);
char_type GetArgSep() const;
void Error(EErrorCodes a_iErrc, int a_iPos = (int)mu::string_type::npos,
const string_type &a_strTok = string_type()) const;
ParserError Error(EErrorCodes a_iErrc, int a_iPos = (int)mu::string_type::npos,
const string_type &a_strTok = string_type()) const;
protected:
void Init();
@@ -213,8 +216,8 @@ class ParserBase {
void InitTokenReader();
void ReInit() const;
void AddCallback(const string_type &a_strName, const ParserCallback &a_Callback,
funmap_type &a_Storage, const char_type *a_szCharSet);
OptionalError AddCallback(const string_type &a_strName, const ParserCallback &a_Callback,
funmap_type &a_Storage, const char_type *a_szCharSet);
OptionalError ApplyRemainingOprt(ParserStack<token_type> &a_stOpt,
ParserStack<token_type> &a_stVal) const;
@@ -240,9 +243,9 @@ class ParserBase {
ValueOrError ParseCmdCodeBulk(int nOffset, int nThreadID) const;
ValueOrError InvokeFunction(generic_fun_type func, const value_type *args, int argCount) const;
void CheckName(const string_type &a_strName, const string_type &a_CharSet) const;
void CheckOprt(const string_type &a_sName, const ParserCallback &a_Callback,
const string_type &a_szCharSet) const;
OptionalError CheckName(const string_type &a_strName, const string_type &a_CharSet) const;
OptionalError CheckOprt(const string_type &a_sName, const ParserCallback &a_Callback,
const string_type &a_szCharSet) const;
void StackDump(const ParserStack<token_type> &a_stVal,
const ParserStack<token_type> &a_stOprt) const;

View File

@@ -288,6 +288,19 @@ enum EErrorCodes {
/// \return an error message for the given code.
string_type parser_error_for_code(EErrorCodes code);
// Compatibility with non-clang compilers.
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
// Define a type-level attribute declaring that this type, when used as the return value
// of a function, should produce warnings.
#if __has_attribute(warn_unused_result)
#define MUPARSER_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define MUPARSER_ATTR_WARN_UNUSED_RESULT
#endif
//---------------------------------------------------------------------------
/** \brief Error class of the parser.
\author Ingo Berg
@@ -326,20 +339,7 @@ class ParserError {
string_type m_strTok; ///< Token related with the error
int m_iPos; ///< Formula position related to the error
EErrorCodes m_iErrc; ///< Error code
};
// Compatibility with non-clang compilers.
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
// Define a type-level attribute declaring that this type, when used as the return value
// of a function, should produce warnings.
#if __has_attribute(warn_unused_result)
#define MUPARSER_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define MUPARSER_ATTR_WARN_UNUSED_RESULT
#endif
} MUPARSER_ATTR_WARN_UNUSED_RESULT;
// OptionalError is used to optionally encapsulate an error.
class OptionalError {

View File

@@ -70,7 +70,7 @@ ValueOrError Parser::ATanh(value_type v) { return MathImpl<value_type>::ATanh(v)
// Logarithm base 2
ValueOrError Parser::Log2(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v <= 0) throw ParserError(ecDOMAIN_ERROR, _T("Log2"));
if (v <= 0) return ParserError(ecDOMAIN_ERROR, _T("Log2"));
#endif
return MathImpl<value_type>::Log2(v);
@@ -79,7 +79,7 @@ ValueOrError Parser::Log2(value_type v) {
// Logarithm base 10
ValueOrError Parser::Log10(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v <= 0) throw ParserError(ecDOMAIN_ERROR, _T("Log10"));
if (v <= 0) return ParserError(ecDOMAIN_ERROR, _T("Log10"));
#endif
return MathImpl<value_type>::Log10(v);
@@ -88,7 +88,7 @@ ValueOrError Parser::Log10(value_type v) {
// Logarithm base e (natural logarithm)
ValueOrError Parser::Ln(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v <= 0) throw ParserError(ecDOMAIN_ERROR, _T("Ln"));
if (v <= 0) return ParserError(ecDOMAIN_ERROR, _T("Ln"));
#endif
return MathImpl<value_type>::Log(v);
@@ -100,7 +100,7 @@ ValueOrError Parser::Exp(value_type v) { return MathImpl<value_type>::Exp(v); }
ValueOrError Parser::Abs(value_type v) { return MathImpl<value_type>::Abs(v); }
ValueOrError Parser::Sqrt(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v < 0) throw ParserError(ecDOMAIN_ERROR, _T("sqrt"));
if (v < 0) return ParserError(ecDOMAIN_ERROR, _T("sqrt"));
#endif
return MathImpl<value_type>::Sqrt(v);
@@ -128,7 +128,7 @@ ValueOrError Parser::UnaryPlus(value_type v) { return v; }
\param [in] a_iArgc The size of a_afArg
*/
ValueOrError Parser::Sum(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw exception_type(_T("too few arguments for function sum."));
if (!a_iArgc) return ParserError(_T("too few arguments for function sum."));
value_type fRes = 0;
for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i];
@@ -141,7 +141,7 @@ ValueOrError Parser::Sum(const value_type *a_afArg, int a_iArgc) {
\param [in] a_iArgc The size of a_afArg
*/
ValueOrError Parser::Avg(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw exception_type(_T("too few arguments for function sum."));
if (!a_iArgc) return ParserError(_T("too few arguments for function sum."));
value_type fRes = 0;
for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i];
@@ -154,7 +154,7 @@ ValueOrError Parser::Avg(const value_type *a_afArg, int a_iArgc) {
\param [in] a_iArgc The size of a_afArg
*/
ValueOrError Parser::Min(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw exception_type(_T("too few arguments for function min."));
if (!a_iArgc) return ParserError(_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]);
@@ -168,7 +168,7 @@ ValueOrError Parser::Min(const value_type *a_afArg, int a_iArgc) {
\param [in] a_iArgc The size of a_afArg
*/
ValueOrError Parser::Max(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw exception_type(_T("too few arguments for function max."));
if (!a_iArgc) return ParserError(_T("too few arguments for function max."));
value_type fRes = a_afArg[0];
for (int i = 0; i < a_iArgc; ++i) fRes = std::max(fRes, a_afArg[i]);
@@ -279,8 +279,13 @@ void Parser::InitFun() {
number ("_e").
*/
void Parser::InitConst() {
DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI);
DefineConst(_T("_e"), (value_type)PARSER_CONST_E);
OptionalError oerr;
oerr = DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI);
assert(!oerr.has_error() && "Error defining _pi constant");
(void)oerr;
oerr = DefineConst(_T("_e"), (value_type)PARSER_CONST_E);
assert(!oerr.has_error() && "Error defining _e constant");
(void)oerr;
}
//---------------------------------------------------------------------------

View File

@@ -219,30 +219,33 @@ void ParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData) {
//---------------------------------------------------------------------------
/** \brief Add a function or operator callback to the parser. */
void ParserBase::AddCallback(const string_type &a_strName, const ParserCallback &a_Callback,
funmap_type &a_Storage, const char_type *a_szCharSet) {
if (a_Callback.GetAddr() == 0) Error(ecINVALID_FUN_PTR);
OptionalError ParserBase::AddCallback(const string_type &a_strName,
const ParserCallback &a_Callback, funmap_type &a_Storage,
const char_type *a_szCharSet) {
assert(a_Callback.GetAddr() && "Null callback");
const funmap_type *pFunMap = &a_Storage;
// Check for conflicting operator or function names
if (pFunMap != &m_FunDef && m_FunDef.find(a_strName) != m_FunDef.end())
Error(ecNAME_CONFLICT, -1, a_strName);
return Error(ecNAME_CONFLICT, -1, a_strName);
if (pFunMap != &m_PostOprtDef && m_PostOprtDef.find(a_strName) != m_PostOprtDef.end())
Error(ecNAME_CONFLICT, -1, a_strName);
return Error(ecNAME_CONFLICT, -1, a_strName);
if (pFunMap != &m_InfixOprtDef && pFunMap != &m_OprtDef &&
m_InfixOprtDef.find(a_strName) != m_InfixOprtDef.end())
Error(ecNAME_CONFLICT, -1, a_strName);
return Error(ecNAME_CONFLICT, -1, a_strName);
if (pFunMap != &m_InfixOprtDef && pFunMap != &m_OprtDef &&
m_OprtDef.find(a_strName) != m_OprtDef.end())
Error(ecNAME_CONFLICT, -1, a_strName);
return Error(ecNAME_CONFLICT, -1, a_strName);
CheckOprt(a_strName, a_Callback, a_szCharSet);
OptionalError oerr = CheckOprt(a_strName, a_Callback, a_szCharSet);
if (oerr.has_error()) return oerr;
a_Storage[a_strName] = a_Callback;
ReInit();
return {};
}
//---------------------------------------------------------------------------
@@ -250,19 +253,20 @@ void ParserBase::AddCallback(const string_type &a_strName, const ParserCallback
\throw ParserException if the name contains invalid characters.
*/
void ParserBase::CheckOprt(const string_type &a_sName, const ParserCallback &a_Callback,
const string_type &a_szCharSet) const {
OptionalError ParserBase::CheckOprt(const string_type &a_sName, const ParserCallback &a_Callback,
const string_type &a_szCharSet) const {
if (!a_sName.length() || (a_sName.find_first_not_of(a_szCharSet) != string_type::npos) ||
(a_sName[0] >= '0' && a_sName[0] <= '9')) {
switch (a_Callback.GetCode()) {
case cmOPRT_POSTFIX:
Error(ecINVALID_POSTFIX_IDENT, -1, a_sName);
return Error(ecINVALID_POSTFIX_IDENT, -1, a_sName);
case cmOPRT_INFIX:
Error(ecINVALID_INFIX_IDENT, -1, a_sName);
return Error(ecINVALID_INFIX_IDENT, -1, a_sName);
default:
Error(ecINVALID_NAME, -1, a_sName);
return Error(ecINVALID_NAME, -1, a_sName);
}
}
return {};
}
//---------------------------------------------------------------------------
@@ -270,11 +274,13 @@ void ParserBase::CheckOprt(const string_type &a_sName, const ParserCallback &a_C
\throw ParserException if the name contains invalid characters.
*/
void ParserBase::CheckName(const string_type &a_sName, const string_type &a_szCharSet) const {
OptionalError ParserBase::CheckName(const string_type &a_sName,
const string_type &a_szCharSet) const {
if (!a_sName.length() || (a_sName.find_first_not_of(a_szCharSet) != string_type::npos) ||
(a_sName[0] >= '0' && a_sName[0] <= '9')) {
Error(ecINVALID_NAME);
return Error(ecINVALID_NAME);
}
return {};
}
//---------------------------------------------------------------------------
@@ -285,11 +291,11 @@ void ParserBase::CheckName(const string_type &a_sName, const string_type &a_szCh
Triggers first time calculation thus the creation of the bytecode and
scanning of used variables.
*/
void ParserBase::SetExpr(const string_type &a_sExpr) {
OptionalError ParserBase::SetExpr(const string_type &a_sExpr) {
// Check locale compatibility
std::locale loc;
if (m_pTokenReader->GetArgSep() == std::use_facet<numpunct<char_type> >(loc).decimal_point())
Error(ecLOCALE);
return Error(ecLOCALE);
// <ibg> 20060222: Bugfix for Borland-Kylix:
// adding a space to the expression will keep Borlands KYLIX from going wild
@@ -299,6 +305,7 @@ void ParserBase::SetExpr(const string_type &a_sExpr) {
string_type sBuf(a_sExpr + _T(" "));
m_pTokenReader->SetFormula(sBuf);
ReInit();
return {};
}
//---------------------------------------------------------------------------
@@ -359,8 +366,9 @@ const char_type *ParserBase::ValidInfixOprtChars() const {
\post Will reset the Parser to string parsing mode.
*/
void ParserBase::DefinePostfixOprt(const string_type &a_sName, fun_type1 a_pFun, bool a_bAllowOpt) {
AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX),
m_PostOprtDef, ValidOprtChars());
auto oerr = AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX),
m_PostOprtDef, ValidOprtChars());
if (oerr.has_error()) throw oerr.error();
}
//---------------------------------------------------------------------------
@@ -386,8 +394,9 @@ void ParserBase::Init() {
*/
void ParserBase::DefineInfixOprt(const string_type &a_sName, fun_type1 a_pFun, int a_iPrec,
bool a_bAllowOpt) {
AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), m_InfixOprtDef,
ValidInfixOprtChars());
auto oerr = AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX),
m_InfixOprtDef, ValidInfixOprtChars());
if (oerr.has_error()) throw oerr.error();
}
//---------------------------------------------------------------------------
@@ -400,14 +409,14 @@ void ParserBase::DefineInfixOprt(const string_type &a_sName, fun_type1 a_pFun, i
Adds a new Binary operator the the parser instance.
*/
void ParserBase::DefineOprt(const string_type &a_sName, fun_type2 a_pFun, unsigned a_iPrec,
EOprtAssociativity a_eAssociativity, bool a_bAllowOpt) {
OptionalError ParserBase::DefineOprt(const string_type &a_sName, fun_type2 a_pFun, unsigned a_iPrec,
EOprtAssociativity a_eAssociativity, bool a_bAllowOpt) {
// Check for conflicts with built in operator names
for (int i = 0; m_bBuiltInOp && i < cmENDIF; ++i)
if (a_sName == string_type(c_DefaultOprt[i])) Error(ecBUILTIN_OVERLOAD, -1, a_sName);
if (a_sName == string_type(c_DefaultOprt[i])) return Error(ecBUILTIN_OVERLOAD, -1, a_sName);
AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, a_eAssociativity), m_OprtDef,
ValidOprtChars());
return AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, a_eAssociativity),
m_OprtDef, ValidOprtChars());
}
//---------------------------------------------------------------------------
@@ -415,16 +424,19 @@ void ParserBase::DefineOprt(const string_type &a_sName, fun_type2 a_pFun, unsign
\param [in] a_strName The name of the constant.
\param [in] a_strVal the value of the constant.
*/
void ParserBase::DefineStrConst(const string_type &a_strName, const string_type &a_strVal) {
OptionalError ParserBase::DefineStrConst(const string_type &a_strName,
const string_type &a_strVal) {
// Test if a constant with that names already exists
if (m_StrVarDef.find(a_strName) != m_StrVarDef.end()) Error(ecNAME_CONFLICT);
if (m_StrVarDef.find(a_strName) != m_StrVarDef.end()) return Error(ecNAME_CONFLICT);
CheckName(a_strName, ValidNameChars());
OptionalError oerr = CheckName(a_strName, ValidNameChars());
if (oerr.has_error()) return oerr;
m_vStringVarBuf.push_back(a_strVal); // Store variable string in internal buffer
m_StrVarDef[a_strName] = m_vStringVarBuf.size() - 1; // bind buffer index to variable name
ReInit();
return {};
}
//---------------------------------------------------------------------------
@@ -434,15 +446,18 @@ void ParserBase::DefineStrConst(const string_type &a_strName, const string_type
\post Will reset the Parser to string parsing mode.
\throw ParserException in case the name contains invalid signs or a_pVar is NULL.
*/
void ParserBase::DefineVar(const string_type &a_sName, value_type *a_pVar) {
if (a_pVar == 0) Error(ecINVALID_VAR_PTR);
OptionalError ParserBase::DefineVar(const string_type &a_sName, value_type *a_pVar) {
assert(a_pVar != nullptr && "Null variable pointer");
// Test if a constant with that names already exists
if (m_ConstDef.find(a_sName) != m_ConstDef.end()) Error(ecNAME_CONFLICT);
if (m_ConstDef.find(a_sName) != m_ConstDef.end()) return Error(ecNAME_CONFLICT);
OptionalError oerr = CheckName(a_sName, ValidNameChars());
if (oerr.has_error()) return oerr;
CheckName(a_sName, ValidNameChars());
m_VarDef[a_sName] = a_pVar;
ReInit();
return {};
}
//---------------------------------------------------------------------------
@@ -452,10 +467,12 @@ void ParserBase::DefineVar(const string_type &a_sName, value_type *a_pVar) {
\post Will reset the Parser to string parsing mode.
\throw ParserException in case the name contains invalid signs.
*/
void ParserBase::DefineConst(const string_type &a_sName, value_type a_fVal) {
CheckName(a_sName, ValidNameChars());
OptionalError ParserBase::DefineConst(const string_type &a_sName, value_type a_fVal) {
OptionalError oerr = CheckName(a_sName, ValidNameChars());
if (oerr.has_error()) return oerr;
m_ConstDef[a_sName] = a_fVal;
ReInit();
return {};
}
//---------------------------------------------------------------------------
@@ -557,7 +574,7 @@ const string_type &ParserBase::GetExpr() const { return m_pTokenReader->GetExpr(
OptionalError ParserBase::ApplyStrFunc(const token_type &a_FunTok,
const std::vector<token_type> &a_vArg) const {
if (a_vArg.back().GetCode() != cmSTRING)
Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
return Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
token_type valTok;
generic_fun_type pFunc = a_FunTok.GetFuncAddr();
@@ -584,7 +601,7 @@ OptionalError ParserBase::ApplyStrFunc(const token_type &a_FunTok,
assert(0 && "Unexpected arg count");
}
if (errored) {
Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
return Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
}
// string functions won't be optimized
@@ -625,13 +642,13 @@ OptionalError ParserBase::ApplyFunc(ParserStack<token_type> &a_stOpt,
assert(0 && "muParser internal error");
if (funTok.GetArgCount() >= 0 && iArgCount > iArgRequired)
Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString());
return Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString());
if (funTok.GetCode() != cmOPRT_BIN && iArgCount < iArgRequired)
Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString());
return Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString());
if (funTok.GetCode() == cmFUNC_STR && iArgCount > iArgRequired)
Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString());
return Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString());
// Collect the numeric function arguments from the value stack and store them
// in a vector
@@ -639,7 +656,7 @@ OptionalError ParserBase::ApplyFunc(ParserStack<token_type> &a_stOpt,
for (int i = 0; i < iArgNumerical; ++i) {
stArg.push_back(a_stVal.pop());
if (stArg.back().GetType() == tpSTR && funTok.GetType() != tpSTR)
Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
return Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
}
switch (funTok.GetCode()) {
@@ -647,7 +664,7 @@ OptionalError ParserBase::ApplyFunc(ParserStack<token_type> &a_stOpt,
stArg.push_back(a_stVal.pop());
if (stArg.back().GetType() == tpSTR && funTok.GetType() != tpSTR)
Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
return Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
OptionalError err = ApplyStrFunc(funTok, stArg);
if (err.has_error()) return err;
@@ -659,7 +676,7 @@ OptionalError ParserBase::ApplyFunc(ParserStack<token_type> &a_stOpt,
case cmOPRT_INFIX:
case cmFUNC:
if (funTok.GetArgCount() == -1 && iArgCount == 0)
Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString());
return Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString());
m_vRPN.AddFun(funTok.GetFuncAddr(),
(funTok.GetArgCount() == -1) ? -iArgNumerical : iArgNumerical);
@@ -723,10 +740,10 @@ OptionalError ParserBase::ApplyBinOprt(ParserStack<token_type> &a_stOpt,
if (valTok1.GetType() != valTok2.GetType() ||
(valTok1.GetType() == tpSTR && valTok2.GetType() == tpSTR))
Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString());
return Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString());
if (optTok.GetCode() == cmASSIGN) {
if (valTok2.GetCode() != cmVAR) Error(ecUNEXPECTED_OPERATOR, -1, _T("="));
if (valTok2.GetCode() != cmVAR) return Error(ecUNEXPECTED_OPERATOR, -1, _T("="));
m_vRPN.AddAssignOp(valTok2.GetVar());
} else
@@ -1023,8 +1040,8 @@ OptionalError ParserBase::CreateRPN() const {
for (;;) {
opt = m_pTokenReader->ReadNextToken();
OptionalError oerr;
OptionalError oerr;
switch (opt.GetCode()) {
//
// Next three are different kind of value entries
@@ -1050,7 +1067,7 @@ OptionalError ParserBase::CreateRPN() const {
case cmELSE:
m_nIfElseCounter--;
if (m_nIfElseCounter < 0) Error(ecMISPLACED_COLON, m_pTokenReader->GetPos());
if (m_nIfElseCounter < 0) return Error(ecMISPLACED_COLON, m_pTokenReader->GetPos());
oerr = ApplyRemainingOprt(stOpt, stVal);
if (oerr.has_error()) return oerr.error();
@@ -1059,7 +1076,8 @@ OptionalError ParserBase::CreateRPN() const {
break;
case cmARG_SEP:
if (stArgCount.empty()) Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos());
if (stArgCount.empty())
return Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos());
++stArgCount.top();
// fallthrough intentional (no break!)
@@ -1096,7 +1114,7 @@ OptionalError ParserBase::CreateRPN() const {
if (iArgCount > 1 &&
(stOpt.size() == 0 ||
(stOpt.top().GetCode() != cmFUNC && stOpt.top().GetCode() != cmFUNC_STR)))
Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos());
return Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos());
// The opening bracket was popped from the stack now check if there
// was a function before this bracket
@@ -1208,16 +1226,16 @@ OptionalError ParserBase::CreateRPN() const {
if (ParserBase::g_DbgDumpCmdCode) m_vRPN.AsciiDump();
if (m_nIfElseCounter > 0) Error(ecMISSING_ELSE_CLAUSE);
if (m_nIfElseCounter > 0) return Error(ecMISSING_ELSE_CLAUSE);
// get the last value (= final result) from the stack
assert(stArgCount.size() == 1 && "Expected arg count of 1");
m_nFinalResultIdx = stArgCount.top();
if (m_nFinalResultIdx == 0) assert(0 && "muParser internal error");
if (stVal.size() == 0) Error(ecEMPTY_EXPRESSION);
if (stVal.size() == 0) return Error(ecEMPTY_EXPRESSION);
if (stVal.top().GetType() != tpDBL) Error(ecSTR_RESULT);
if (stVal.top().GetType() != tpDBL) return Error(ecSTR_RESULT);
m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads);
return {};
@@ -1253,10 +1271,9 @@ ValueOrError ParserBase::ParseString() const {
\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 ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const {
throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos);
ParserError ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const {
return ParserError(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos);
}
//------------------------------------------------------------------------------
@@ -1458,7 +1475,8 @@ void ParserBase::StackDump(const ParserStack<token_type> &a_stVal,
made up of multiple comma separated subexpressions (i.e. "x+y,sin(x),cos(y)")
*/
void ParserBase::Eval(std::vector<ValueOrError> *outResult) const {
(this->*m_pParseFormula)();
ValueOrError v = (this->*m_pParseFormula)();
if (v.has_error()) throw v.error();
int stackSize = m_nFinalResultIdx;
// (for historic reasons the stack starts at position 1)

View File

@@ -71,7 +71,7 @@ ValueOrError ParserInt::UnaryMinus(value_type v) { return -Round(v); }
//---------------------------------------------------------------------------
ValueOrError ParserInt::Sum(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw ParserError(_T("too few arguments for function sum."));
if (!a_iArgc) return ParserError(_T("too few arguments for function sum."));
value_type fRes = 0;
for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i];
@@ -81,7 +81,7 @@ ValueOrError ParserInt::Sum(const value_type *a_afArg, int a_iArgc) {
//---------------------------------------------------------------------------
ValueOrError ParserInt::Min(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw ParserError(_T("too few arguments for function min."));
if (!a_iArgc) return ParserError(_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]);
@@ -91,7 +91,7 @@ ValueOrError ParserInt::Min(const value_type *a_afArg, int a_iArgc) {
//---------------------------------------------------------------------------
ValueOrError ParserInt::Max(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw ParserError(_T("too few arguments for function min."));
if (!a_iArgc) return ParserError(_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]);
@@ -219,28 +219,28 @@ void ParserInt::InitOprt() {
DefineInfixOprt(_T("-"), UnaryMinus);
DefineInfixOprt(_T("!"), Not);
DefineOprt(_T("&"), LogAnd, prLOGIC);
DefineOprt(_T("|"), LogOr, prLOGIC);
DefineOprt(_T("&&"), And, prLOGIC);
DefineOprt(_T("||"), Or, prLOGIC);
(void)DefineOprt(_T("&"), LogAnd, prLOGIC);
(void)DefineOprt(_T("|"), LogOr, prLOGIC);
(void)DefineOprt(_T("&&"), And, prLOGIC);
(void)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);
(void)DefineOprt(_T("<"), Less, prCMP);
(void)DefineOprt(_T(">"), Greater, prCMP);
(void)DefineOprt(_T("<="), LessEq, prCMP);
(void)DefineOprt(_T(">="), GreaterEq, prCMP);
(void)DefineOprt(_T("=="), Equal, prCMP);
(void)DefineOprt(_T("!="), NotEqual, prCMP);
DefineOprt(_T("+"), Add, prADD_SUB);
DefineOprt(_T("-"), Sub, prADD_SUB);
(void)DefineOprt(_T("+"), Add, prADD_SUB);
(void)DefineOprt(_T("-"), Sub, prADD_SUB);
DefineOprt(_T("*"), Mul, prMUL_DIV);
DefineOprt(_T("/"), Div, prMUL_DIV);
DefineOprt(_T("%"), Mod, prMUL_DIV);
(void)DefineOprt(_T("*"), Mul, prMUL_DIV);
(void)DefineOprt(_T("/"), Div, prMUL_DIV);
(void)DefineOprt(_T("%"), Mod, prMUL_DIV);
DefineOprt(_T("^"), Pow, prPOW, oaRIGHT);
DefineOprt(_T(">>"), Shr, prMUL_DIV + 1);
DefineOprt(_T("<<"), Shl, prMUL_DIV + 1);
(void)DefineOprt(_T("^"), Pow, prPOW, oaRIGHT);
(void)DefineOprt(_T(">>"), Shr, prMUL_DIV + 1);
(void)DefineOprt(_T("<<"), Shl, prMUL_DIV + 1);
}
} // namespace mu