From 91c28449aab8196ea6a59f2990969bdec48f2e79 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Fri, 24 Nov 2017 23:55:51 -0800 Subject: [PATCH] [muparser] Parser mathematical functions to return errors instead of throw Remove exceptions from Parser functions such as sqrt, min, and others. --- muparser-2.2.5/include/muParserBase.h | 31 +++--- muparser-2.2.5/include/muParserDef.h | 28 +++--- muparser-2.2.5/src/muParser.cpp | 25 +++-- muparser-2.2.5/src/muParserBase.cpp | 130 +++++++++++++++----------- muparser-2.2.5/src/muParserInt.cpp | 42 ++++----- src/builtin_math.cpp | 6 +- 6 files changed, 146 insertions(+), 116 deletions(-) diff --git a/muparser-2.2.5/include/muParserBase.h b/muparser-2.2.5/include/muParserBase.h index 52291748f..ec268779b 100644 --- a/muparser-2.2.5/include/muParserBase.h +++ b/muparser-2.2.5/include/muParserBase.h @@ -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 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 &a_stOpt, ParserStack &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 &a_stVal, const ParserStack &a_stOprt) const; diff --git a/muparser-2.2.5/include/muParserDef.h b/muparser-2.2.5/include/muParserDef.h index 24bcbc801..e309af55d 100644 --- a/muparser-2.2.5/include/muParserDef.h +++ b/muparser-2.2.5/include/muParserDef.h @@ -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 { diff --git a/muparser-2.2.5/src/muParser.cpp b/muparser-2.2.5/src/muParser.cpp index 5e4e7bb25..96af93de9 100644 --- a/muparser-2.2.5/src/muParser.cpp +++ b/muparser-2.2.5/src/muParser.cpp @@ -70,7 +70,7 @@ ValueOrError Parser::ATanh(value_type v) { return MathImpl::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::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::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::Log(v); @@ -100,7 +100,7 @@ ValueOrError Parser::Exp(value_type v) { return MathImpl::Exp(v); } ValueOrError Parser::Abs(value_type v) { return MathImpl::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::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; } //--------------------------------------------------------------------------- diff --git a/muparser-2.2.5/src/muParserBase.cpp b/muparser-2.2.5/src/muParserBase.cpp index 3a571d217..ba0a2c893 100644 --- a/muparser-2.2.5/src/muParserBase.cpp +++ b/muparser-2.2.5/src/muParserBase.cpp @@ -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 >(loc).decimal_point()) - Error(ecLOCALE); + return Error(ecLOCALE); // 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 &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 &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 &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 &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 &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 &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 &a_stVal, made up of multiple comma separated subexpressions (i.e. "x+y,sin(x),cos(y)") */ void ParserBase::Eval(std::vector *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) diff --git a/muparser-2.2.5/src/muParserInt.cpp b/muparser-2.2.5/src/muParserInt.cpp index 7523a636c..aa9ee6a01 100644 --- a/muparser-2.2.5/src/muParserInt.cpp +++ b/muparser-2.2.5/src/muParserInt.cpp @@ -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 diff --git a/src/builtin_math.cpp b/src/builtin_math.cpp index 196ce32ad..ba61af8fb 100644 --- a/src/builtin_math.cpp +++ b/src/builtin_math.cpp @@ -130,9 +130,13 @@ static int evaluate_expression(wchar_t *cmd, parser_t &parser, io_streams_t &str p.DefineOprtChars(L"%"); p.DefineOprt(L"%", moduloOperator, mu::prINFIX); - p.SetExpr(expression); + mu::OptionalError oerr = p.SetExpr(expression); + if (oerr.has_error()) throw oerr.error(); std::vector vs; p.Eval(&vs); + for (const mu::ValueOrError &v : vs) { + if (v.has_error()) throw v.error(); + } for (const mu::ValueOrError &v : vs) { if (opts.scale == 0) { streams.out.append_format(L"%ld\n", static_cast(*v));