From a815443e037ece09528929dbaa3d9810485c7917 Mon Sep 17 00:00:00 2001 From: Ingo Berg Date: Sat, 14 Oct 2023 22:56:06 +0200 Subject: [PATCH] update added error to warn about using bytecode export and variable factories. I did not enable the error. It is not necessarily a problem just tricky to manage. --- include/muParserBytecode.h | 6 +- include/muParserDef.h | 4 +- include/muParserTokenReader.h | 9 + samples/example1/example1.cpp | 1 + src/muParserBase.cpp | 10 + src/muParserError.cpp | 671 +++++++++++++++++----------------- 6 files changed, 362 insertions(+), 339 deletions(-) diff --git a/include/muParserBytecode.h b/include/muParserBytecode.h index bf84dd7..35e1dbe 100644 --- a/include/muParserBytecode.h +++ b/include/muParserBytecode.h @@ -151,10 +151,10 @@ namespace mu return &m_vRPN[0]; } - void StoreEnvironment(string_type a_expr, stringbuf_type const& a_strBuf) + void StoreEnvironment(string_type expr, stringbuf_type const& strBuf) { - m_stringBuffer = a_strBuf; - m_expr = a_expr; + m_stringBuffer = strBuf; + m_expr = expr; } std::tuple RestoreEnvironment() const diff --git a/include/muParserDef.h b/include/muParserDef.h index 571dd81..d36dbe3 100644 --- a/include/muParserDef.h +++ b/include/muParserDef.h @@ -276,7 +276,9 @@ namespace mu ecINVALID_CHARACTERS_FOUND = 38,///< The expression or identifier contains invalid non printable characters // internal errors - ecINTERNAL_ERROR = 39, ///< Internal error of any kind. + ecINTERNAL_ERROR = 39, ///< Internal error of any kind. + + ecBYTECODE_IMPORT_EXPORT_DISABLED = 40, ///< Bytecode cannot be exported. // The last two are special entries ecCOUNT, ///< This is no error code, It just stores just the total number of error codes diff --git a/include/muParserTokenReader.h b/include/muParserTokenReader.h index c81ffab..b3739fa 100644 --- a/include/muParserTokenReader.h +++ b/include/muParserTokenReader.h @@ -67,6 +67,15 @@ namespace mu void SetFormula(const string_type& a_strFormula); void SetArgSep(char_type cArgSep); + /** \brief Check whether a variable factory is installed. + + Variable factories automatically create new variables when a unknown variable is found in an expression. + */ + bool HasVarCreator() const + { + return m_pFactory != nullptr; + } + int GetPos() const; const string_type& GetExpr() const; varmap_type& GetUsedVar(); diff --git a/samples/example1/example1.cpp b/samples/example1/example1.cpp index 5577aa7..89a59c2 100644 --- a/samples/example1/example1.cpp +++ b/samples/example1/example1.cpp @@ -39,6 +39,7 @@ #include "muParserTest.h" #include "muParser.h" +#include "muParserBytecode.h" using namespace std; using namespace mu; diff --git a/src/muParserBase.cpp b/src/muParserBase.cpp index b42ac91..5ffbb49 100644 --- a/src/muParserBase.cpp +++ b/src/muParserBase.cpp @@ -270,6 +270,11 @@ namespace mu */ const ParserByteCode& ParserBase::GetByteCode() const { + // If a variable factory is defined the bytecode may contain references to implicitely + // created variables. +// if (m_pTokenReader->HasVarCreator()) +// Error(ecBYTECODE_IMPORT_EXPORT_DISABLED); + return m_vRPN; } @@ -277,6 +282,11 @@ namespace mu /** \brief Restore a previously saved bytecode. */ void ParserBase::SetByteCode(const ParserByteCode& a_ByteCode) { + // If a variable factory is defined the bytecode may contain references to dynamically + // created variables. +// if (m_pTokenReader->HasVarCreator()) +// Error(ecBYTECODE_IMPORT_EXPORT_DISABLED); + m_vRPN = a_ByteCode; // restore expression environment diff --git a/src/muParserError.cpp b/src/muParserError.cpp index 612dae3..4312dc6 100644 --- a/src/muParserError.cpp +++ b/src/muParserError.cpp @@ -1,335 +1,336 @@ -/* - - _____ __ _____________ _______ ______ ___________ - / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ - | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ - |__|_| /____/| __(____ /__| /____ >\___ >__| - \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2022 Ingo Berg - - Redistribution and use in source and binary forms, with or without modification, are permitted - provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of - conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of - conditions and the following disclaimer in the documentation and/or other materials provided - with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "muParserError.h" -#include - -#if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable : 26812) // MSVC wants to force me te use enum classes or bother me with pointless warnings -#endif - -namespace mu -{ - //------------------------------------------------------------------------------ - const ParserErrorMsg& ParserErrorMsg::Instance() - { - static const ParserErrorMsg instance; - return instance; - } - - //------------------------------------------------------------------------------ - string_type ParserErrorMsg::operator[](unsigned a_iIdx) const - { - return (a_iIdx < m_vErrMsg.size()) ? m_vErrMsg[a_iIdx] : string_type(); - } - - //--------------------------------------------------------------------------- - ParserErrorMsg::ParserErrorMsg() - :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("Strings must only be used as function arguments!"); - 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 preceded 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$"); - m_vErrMsg[ecUNREASONABLE_NUMBER_OF_COMPUTATIONS] = _T("Number of computations to small for bulk mode. (Vectorisation overhead too costly)"); - m_vErrMsg[ecIDENTIFIER_TOO_LONG] = _T("Identifier too long."); - m_vErrMsg[ecEXPRESSION_TOO_LONG] = _T("Expression too long."); - m_vErrMsg[ecINVALID_CHARACTERS_FOUND] = _T("Invalid non printable characters found in expression/identifer!"); - - for (int i = 0; i < ecCOUNT; ++i) - { - if (!m_vErrMsg[i].length()) - throw std::runtime_error("Error definitions are incomplete!"); - } - } - - //--------------------------------------------------------------------------- - // - // ParserError class - // - //--------------------------------------------------------------------------- - - /** \brief Default constructor. */ - ParserError::ParserError() - :m_strMsg() - , m_strFormula() - , m_strTok() - , m_iPos(-1) - , m_iErrc(ecUNDEFINED) - , m_ErrMsg(ParserErrorMsg::Instance()) - { - } - - //------------------------------------------------------------------------------ - /** \brief This Constructor is used for internal exceptions only. - - It does not contain any information but the error code. - */ - ParserError::ParserError(EErrorCodes a_iErrc) - :m_strMsg() - , m_strFormula() - , m_strTok() - , m_iPos(-1) - , m_iErrc(a_iErrc) - , m_ErrMsg(ParserErrorMsg::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. */ - ParserError::ParserError(const string_type& sMsg) - :m_ErrMsg(ParserErrorMsg::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 occurred. - */ - ParserError::ParserError(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(ParserErrorMsg::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 occurred. - \param [in] sTok The token string related to this error. - */ - ParserError::ParserError(EErrorCodes iErrc, int iPos, const string_type& sTok) - :m_strMsg() - , m_strFormula() - , m_strTok(sTok) - , m_iPos(iPos) - , m_iErrc(iErrc) - , m_ErrMsg(ParserErrorMsg::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. - */ - ParserError::ParserError(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(ParserErrorMsg::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. */ - ParserError::ParserError(const ParserError& 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(ParserErrorMsg::Instance()) - { - } - - //------------------------------------------------------------------------------ - /** \brief Assignment operator. */ - ParserError& ParserError::operator=(const ParserError& 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; - } - - //------------------------------------------------------------------------------ - ParserError::~ParserError() - {} - - //------------------------------------------------------------------------------ - /** \brief Replace all occurrences 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 ParserError::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 error object. */ - void ParserError::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 ParserError::SetFormula(const string_type& a_strFormula) - { - m_strFormula = a_strFormula; - } - - //------------------------------------------------------------------------------ - /** \brief gets the expression related tp this error.*/ - const string_type& ParserError::GetExpr() const - { - return m_strFormula; - } - - //------------------------------------------------------------------------------ - /** \brief Returns the message string for this error. */ - const string_type& ParserError::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 - */ - int ParserError::GetPos() const - { - return m_iPos; - } - - //------------------------------------------------------------------------------ - /** \brief Return string related with this token (if available). */ - const string_type& ParserError::GetToken() const - { - return m_strTok; - } - - //------------------------------------------------------------------------------ - /** \brief Return the error code. */ - EErrorCodes ParserError::GetCode() const - { - return m_iErrc; - } -} // namespace mu - -#if defined(_MSC_VER) - #pragma warning(pop) -#endif +/* + + _____ __ _____________ _______ ______ ___________ + / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ + | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ + |__|_| /____/| __(____ /__| /____ >\___ >__| + \/ |__| \/ \/ \/ + Copyright (C) 2004 - 2022 Ingo Berg + + Redistribution and use in source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials provided + with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "muParserError.h" +#include + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable : 26812) // MSVC wants to force me te use enum classes or bother me with pointless warnings +#endif + +namespace mu +{ + //------------------------------------------------------------------------------ + const ParserErrorMsg& ParserErrorMsg::Instance() + { + static const ParserErrorMsg instance; + return instance; + } + + //------------------------------------------------------------------------------ + string_type ParserErrorMsg::operator[](unsigned a_iIdx) const + { + return (a_iIdx < m_vErrMsg.size()) ? m_vErrMsg[a_iIdx] : string_type(); + } + + //--------------------------------------------------------------------------- + ParserErrorMsg::ParserErrorMsg() + :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("Strings must only be used as function arguments!"); + 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 preceded 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$"); + m_vErrMsg[ecUNREASONABLE_NUMBER_OF_COMPUTATIONS] = _T("Number of computations to small for bulk mode. (Vectorisation overhead too costly)"); + m_vErrMsg[ecIDENTIFIER_TOO_LONG] = _T("Identifier too long."); + m_vErrMsg[ecEXPRESSION_TOO_LONG] = _T("Expression too long."); + m_vErrMsg[ecINVALID_CHARACTERS_FOUND] = _T("Invalid non printable characters found in expression/identifer!"); + m_vErrMsg[ecBYTECODE_IMPORT_EXPORT_DISABLED] = _T("Bytecode cannot be imported or exported when parser is using a variable factory!"); + + for (int i = 0; i < ecCOUNT; ++i) + { + if (!m_vErrMsg[i].length()) + throw std::runtime_error("Error definitions are incomplete!"); + } + } + + //--------------------------------------------------------------------------- + // + // ParserError class + // + //--------------------------------------------------------------------------- + + /** \brief Default constructor. */ + ParserError::ParserError() + :m_strMsg() + , m_strFormula() + , m_strTok() + , m_iPos(-1) + , m_iErrc(ecUNDEFINED) + , m_ErrMsg(ParserErrorMsg::Instance()) + { + } + + //------------------------------------------------------------------------------ + /** \brief This Constructor is used for internal exceptions only. + + It does not contain any information but the error code. + */ + ParserError::ParserError(EErrorCodes a_iErrc) + :m_strMsg() + , m_strFormula() + , m_strTok() + , m_iPos(-1) + , m_iErrc(a_iErrc) + , m_ErrMsg(ParserErrorMsg::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. */ + ParserError::ParserError(const string_type& sMsg) + :m_ErrMsg(ParserErrorMsg::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 occurred. + */ + ParserError::ParserError(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(ParserErrorMsg::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 occurred. + \param [in] sTok The token string related to this error. + */ + ParserError::ParserError(EErrorCodes iErrc, int iPos, const string_type& sTok) + :m_strMsg() + , m_strFormula() + , m_strTok(sTok) + , m_iPos(iPos) + , m_iErrc(iErrc) + , m_ErrMsg(ParserErrorMsg::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. + */ + ParserError::ParserError(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(ParserErrorMsg::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. */ + ParserError::ParserError(const ParserError& 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(ParserErrorMsg::Instance()) + { + } + + //------------------------------------------------------------------------------ + /** \brief Assignment operator. */ + ParserError& ParserError::operator=(const ParserError& 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; + } + + //------------------------------------------------------------------------------ + ParserError::~ParserError() + {} + + //------------------------------------------------------------------------------ + /** \brief Replace all occurrences 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 ParserError::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 error object. */ + void ParserError::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 ParserError::SetFormula(const string_type& a_strFormula) + { + m_strFormula = a_strFormula; + } + + //------------------------------------------------------------------------------ + /** \brief gets the expression related tp this error.*/ + const string_type& ParserError::GetExpr() const + { + return m_strFormula; + } + + //------------------------------------------------------------------------------ + /** \brief Returns the message string for this error. */ + const string_type& ParserError::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 + */ + int ParserError::GetPos() const + { + return m_iPos; + } + + //------------------------------------------------------------------------------ + /** \brief Return string related with this token (if available). */ + const string_type& ParserError::GetToken() const + { + return m_strTok; + } + + //------------------------------------------------------------------------------ + /** \brief Return the error code. */ + EErrorCodes ParserError::GetCode() const + { + return m_iErrc; + } +} // namespace mu + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif