diff --git a/include/muParser.h b/include/muParser.h index 52e25c3..62032aa 100644 --- a/include/muParser.h +++ b/include/muParser.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/include/muParserBase.h b/include/muParserBase.h index 570b7e8..6d32f2f 100644 --- a/include/muParserBase.h +++ b/include/muParserBase.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -176,6 +176,7 @@ namespace mu const string_type& GetExpr() const; const funmap_type& GetFunDef() const; string_type GetVersion(EParserVersionInfo eInfo = pviFULL) const; + const ParserByteCode& GetByteCode() const; const char_type** GetOprtDef() const; void DefineNameChars(const char_type* a_szCharset); @@ -214,9 +215,9 @@ namespace mu explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) :std::numpunct() - , m_nGroup(nGroup) - , m_cDecPoint(cDecSep) - , m_cThousandsSep(cThousandsSep) + ,m_nGroup(nGroup) + ,m_cDecPoint(cDecSep) + ,m_cThousandsSep(cThousandsSep) {} protected: diff --git a/include/muParserBytecode.h b/include/muParserBytecode.h index 91716c5..6854640 100644 --- a/include/muParserBytecode.h +++ b/include/muParserBytecode.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -50,14 +50,14 @@ namespace mu union { - struct //SValData + struct // SValData { value_type* ptr; value_type data; value_type data2; } Val; - struct //SFunData + struct // SFunData { // Note: the type is erased in generic_callable_type and the signature of the // function to call is tracked elsewhere in regard with the number of @@ -68,7 +68,7 @@ namespace mu int idx; } Fun; - struct //SOprtData + struct // SOprtData { value_type* ptr; int offset; diff --git a/include/muParserCallback.h b/include/muParserCallback.h index 7eeb03f..2d804ee 100644 --- a/include/muParserCallback.h +++ b/include/muParserCallback.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/include/muParserDLL.h b/include/muParserDLL.h index 7c75d2a..00eea9f 100644 --- a/include/muParserDLL.h +++ b/include/muParserDLL.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/include/muParserDef.h b/include/muParserDef.h index 2ce779d..4986a57 100644 --- a/include/muParserDef.h +++ b/include/muParserDef.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/include/muParserError.h b/include/muParserError.h index b52d414..90fbfdf 100644 --- a/include/muParserError.h +++ b/include/muParserError.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/include/muParserFixes.h b/include/muParserFixes.h index 59aecad..8042d28 100644 --- a/include/muParserFixes.h +++ b/include/muParserFixes.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/include/muParserInt.h b/include/muParserInt.h index 7f55eed..513f092 100644 --- a/include/muParserInt.h +++ b/include/muParserInt.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/include/muParserTemplateMagic.h b/include/muParserTemplateMagic.h index 015cf14..77fe549 100644 --- a/include/muParserTemplateMagic.h +++ b/include/muParserTemplateMagic.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/include/muParserTest.h b/include/muParserTest.h index b00c15c..c7fd166 100644 --- a/include/muParserTest.h +++ b/include/muParserTest.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -179,35 +179,61 @@ namespace mu } // 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; } + 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); // With user data - static value_type FunUd0(void* data) { return reinterpret_cast(data); } - static value_type FunUd1(void* data, value_type v) { return reinterpret_cast(data) + v; } - static value_type FunUd2(void* data, value_type v1, value_type v2) { return reinterpret_cast(data) + v1 + v2; } - static value_type FunUd10(void* data, value_type v1, value_type v2, value_type v3, value_type v4, value_type v5, - value_type v6, value_type v7, value_type v8, value_type v9, value_type v10) + static value_type FunUd0(void* data) + { + return reinterpret_cast(data); + } + + static value_type FunUd1(void* data, value_type v) + { + return reinterpret_cast(data) + v; + } + + static value_type FunUd2(void* data, value_type v1, value_type v2) + { + return reinterpret_cast(data) + v1 + v2; + } + + static value_type FunUd10(void* data, value_type v1, value_type v2, value_type v3, value_type v4, value_type v5, value_type v6, value_type v7, value_type v8, value_type v9, value_type v10) { return reinterpret_cast(data) + v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10; } + static value_type StrFunUd3(void* data, const char_type* v1, value_type v2, value_type v3) { int val(0); stringstream_type(v1) >> val; return reinterpret_cast(data) + val + v2 + v3; } + static value_type SumUd(void* data, const value_type* a_afArg, int a_iArgc) { if (!a_iArgc) throw mu::Parser::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]; + for (int i = 0; i < a_iArgc; ++i) + fRes += a_afArg[i]; + return reinterpret_cast(data) + fRes; } @@ -225,6 +251,7 @@ namespace mu int TestIfThenElse(); int TestBulkMode(); int TestOssFuzzTestCases(); + int TestOptimizer(); void Abort() const; diff --git a/include/muParserToken.h b/include/muParserToken.h index 079b6e8..b5aec5c 100644 --- a/include/muParserToken.h +++ b/include/muParserToken.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -68,19 +68,22 @@ namespace mu { // Note: we keep generic_callable_type a pod for the purpose of layout - erased_fun_type pRawFun_; - void* pUserData_; + erased_fun_type _pRawFun; + void* _pUserData; template value_type call_fun(Args&&... args) const { static_assert(NbParams == sizeof...(Args), "mismatch between NbParams and Args"); - if (pUserData_ == nullptr) { - auto fun_typed_ptr = reinterpret_cast::fun_type>(pRawFun_); + if (_pUserData == nullptr) + { + auto fun_typed_ptr = reinterpret_cast::fun_type>(_pRawFun); return (*fun_typed_ptr)(std::forward(args)...); - } else { - auto fun_userdata_typed_ptr = reinterpret_cast::fun_userdata_type>(pRawFun_); - return (*fun_userdata_typed_ptr)(pUserData_, std::forward(args)...); + } + else + { + auto fun_userdata_typed_ptr = reinterpret_cast::fun_userdata_type>(_pRawFun); + return (*fun_userdata_typed_ptr)(_pUserData, std::forward(args)...); } } @@ -88,23 +91,23 @@ namespace mu value_type call_bulkfun(Args&&... args) const { static_assert(NbParams == sizeof...(Args) - 2, "mismatch between NbParams and Args"); - if (pUserData_ == nullptr) { - auto bulkfun_typed_ptr = reinterpret_cast::bulkfun_type>(pRawFun_); + if (_pUserData == nullptr) { + auto bulkfun_typed_ptr = reinterpret_cast::bulkfun_type>(_pRawFun); return (*bulkfun_typed_ptr)(std::forward(args)...); } else { - auto bulkfun_userdata_typed_ptr = reinterpret_cast::bulkfun_userdata_type>(pRawFun_); - return (*bulkfun_userdata_typed_ptr)(pUserData_, std::forward(args)...); + auto bulkfun_userdata_typed_ptr = reinterpret_cast::bulkfun_userdata_type>(_pRawFun); + return (*bulkfun_userdata_typed_ptr)(_pUserData, std::forward(args)...); } } value_type call_multfun(const value_type* a_afArg, int a_iArgc) const { - if (pUserData_ == nullptr) { - auto multfun_typed_ptr = reinterpret_cast(pRawFun_); + if (_pUserData == nullptr) { + auto multfun_typed_ptr = reinterpret_cast(_pRawFun); return (*multfun_typed_ptr)(a_afArg, a_iArgc); } else { - auto multfun_userdata_typed_ptr = reinterpret_cast(pRawFun_); - return (*multfun_userdata_typed_ptr)(pUserData_, a_afArg, a_iArgc); + auto multfun_userdata_typed_ptr = reinterpret_cast(_pRawFun); + return (*multfun_userdata_typed_ptr)(_pUserData, a_afArg, a_iArgc); } } @@ -112,20 +115,39 @@ namespace mu value_type call_strfun(Args&&... args) const { static_assert(NbParams == sizeof...(Args), "mismatch between NbParams and Args"); - if (pUserData_ == nullptr) { - auto strfun_typed_ptr = reinterpret_cast::strfun_type>(pRawFun_); + if (_pUserData == nullptr) + { + auto strfun_typed_ptr = reinterpret_cast::strfun_type>(_pRawFun); return (*strfun_typed_ptr)(std::forward(args)...); - } else { - auto strfun_userdata_typed_ptr = reinterpret_cast::strfun_userdata_type>(pRawFun_); - return (*strfun_userdata_typed_ptr)(pUserData_, std::forward(args)...); + } + else + { + auto strfun_userdata_typed_ptr = reinterpret_cast::strfun_userdata_type>(_pRawFun); + return (*strfun_userdata_typed_ptr)(_pUserData, std::forward(args)...); } } - bool operator==(generic_callable_type other) const { return pRawFun_ == other.pRawFun_ && pUserData_ == other.pUserData_; } - explicit operator bool() const { return pRawFun_ != nullptr; } - bool operator==(std::nullptr_t) const { return pRawFun_ == nullptr; } - bool operator!=(std::nullptr_t) const { return pRawFun_ != nullptr; } + bool operator==(generic_callable_type other) const + { + return _pRawFun == other._pRawFun && _pUserData == other._pUserData; + } + + explicit operator bool() const + { + return _pRawFun != nullptr; + } + + bool operator==(std::nullptr_t) const + { + return _pRawFun == nullptr; + } + + bool operator!=(std::nullptr_t) const + { + return _pRawFun != nullptr; + } }; + static_assert(std::is_trivial::value, "generic_callable_type shall be trivial"); static_assert(std::is_standard_layout::value, "generic_callable_type shall have standard layout"); // C++17: static_assert(std::is_aggregate::value, "generic_callable_type shall be an aggregate"); diff --git a/include/muParserTokenReader.h b/include/muParserTokenReader.h index caeb920..0ea19f5 100644 --- a/include/muParserTokenReader.h +++ b/include/muParserTokenReader.h @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/samples/example1/example1.cpp b/samples/example1/example1.cpp index 30b4dd7..1b3461c 100644 --- a/samples/example1/example1.cpp +++ b/samples/example1/example1.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -455,7 +455,7 @@ static void Calc() parser.DefineFun(_T("strfun0"), StrFun0); parser.DefineFun(_T("strfun2"), StrFun2); parser.DefineFun(_T("ping"), Ping); - parser.DefineFun(_T("rnd"), Rnd); // Add an unoptimizeable function + parser.DefineFun(_T("rnd"), Rnd, false); // Add an unoptimizeable function parser.DefineFun(_T("throw"), ThrowAnException); parser.DefineOprt(_T("add"), Add, 0); @@ -466,7 +466,7 @@ static void Calc() parser.DefineFun(_T("selftest"), SelfTest); parser.DefineFun(_T("help"), Help); parser.DefineFun(_T("arg2of2"), Arg2Of2); - parser.DefineFun(_T("arg1of2"), Arg1Of2); + parser.DefineFun(_T("arg1of2"), Arg1Of2, false); parser.DefinePostfixOprt(_T("{ft}"), Milli); parser.DefinePostfixOprt(_T("ft"), Milli); diff --git a/samples/example2/example2.c b/samples/example2/example2.c index 4b89244..42e4564 100644 --- a/samples/example2/example2.c +++ b/samples/example2/example2.c @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/samples/example3/example3.cpp b/samples/example3/example3.cpp index 78df86f..86a2ae2 100644 --- a/samples/example3/example3.cpp +++ b/samples/example3/example3.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/muParser.cpp b/src/muParser.cpp index d134015..0ebef2a 100644 --- a/src/muParser.cpp +++ b/src/muParser.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/muParserBase.cpp b/src/muParserBase.cpp index 9e93936..e775351 100644 --- a/src/muParserBase.cpp +++ b/src/muParserBase.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -265,6 +265,14 @@ namespace mu void ParserBase::OnDetectVar(string_type* /*pExpr*/, int& /*nStart*/, int& /*nEnd*/) {} + //--------------------------------------------------------------------------- + /** \brief Returns the bytecode of the current expression. + */ + const ParserByteCode& ParserBase::GetByteCode() const + { + return m_vRPN; + } + //--------------------------------------------------------------------------- /** \brief Returns the version of muparser. \param eInfo A flag indicating whether the full version info should be @@ -334,7 +342,8 @@ namespace mu //--------------------------------------------------------------------------- /** \brief Add a function or operator callback to the parser. */ - void ParserBase::AddCallback(const string_type& a_strName, + void ParserBase::AddCallback( + const string_type& a_strName, const ParserCallback& a_Callback, funmap_type& a_Storage, const char_type* a_szCharSet) @@ -744,7 +753,8 @@ namespace mu \param a_FunTok Function token. \throw exception_type If the function token is not a string function */ - ParserBase::token_type ParserBase::ApplyStrFunc(const token_type& a_FunTok, + ParserBase::token_type ParserBase::ApplyStrFunc( + const token_type& a_FunTok, const std::vector& a_vArg) const { if (a_vArg.back().GetCode() != cmSTRING) diff --git a/src/muParserBytecode.cpp b/src/muParserBytecode.cpp index 2c01a65..972a758 100644 --- a/src/muParserBytecode.cpp +++ b/src/muParserBytecode.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -587,8 +587,8 @@ namespace mu 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 << reinterpret_cast(m_vRPN[i].Fun.cb.pRawFun_) << _T("]"); - mu::console() << _T("[USERDATA: 0x") << std::hex << reinterpret_cast(m_vRPN[i].Fun.cb.pUserData_) << _T("]"); + mu::console() << _T("[ADDR: 0x") << std::hex << reinterpret_cast(m_vRPN[i].Fun.cb._pRawFun) << _T("]"); + mu::console() << _T("[USERDATA: 0x") << std::hex << reinterpret_cast(m_vRPN[i].Fun.cb._pUserData) << _T("]"); mu::console() << _T("\n"); break; @@ -596,8 +596,8 @@ namespace mu 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") << std::hex << reinterpret_cast(m_vRPN[i].Fun.cb.pRawFun_) << _T("]"); - mu::console() << _T("[USERDATA: 0x") << std::hex << reinterpret_cast(m_vRPN[i].Fun.cb.pUserData_) << _T("]"); + mu::console() << _T("[ADDR: 0x") << std::hex << reinterpret_cast(m_vRPN[i].Fun.cb._pRawFun) << _T("]"); + mu::console() << _T("[USERDATA: 0x") << std::hex << reinterpret_cast(m_vRPN[i].Fun.cb._pUserData) << _T("]"); mu::console() << _T("\n"); break; diff --git a/src/muParserCallback.cpp b/src/muParserCallback.cpp index b765d84..6e78816 100644 --- a/src/muParserCallback.cpp +++ b/src/muParserCallback.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/muParserDLL.cpp b/src/muParserDLL.cpp index a10cbae..846f65e 100644 --- a/src/muParserDLL.cpp +++ b/src/muParserDLL.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/muParserError.cpp b/src/muParserError.cpp index 178ca64..960e48a 100644 --- a/src/muParserError.cpp +++ b/src/muParserError.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/muParserInt.cpp b/src/muParserInt.cpp index f79ba1a..76189e9 100644 --- a/src/muParserInt.cpp +++ b/src/muParserInt.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/muParserTest.cpp b/src/muParserTest.cpp index 5cb5ef8..20727d7 100644 --- a/src/muParserTest.cpp +++ b/src/muParserTest.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -62,6 +62,7 @@ namespace mu AddTest(&ParserTester::TestException); AddTest(&ParserTester::TestStrArg); AddTest(&ParserTester::TestBulkMode); + AddTest(&ParserTester::TestOptimizer); ParserTester::c_iCount = 0; } @@ -130,6 +131,44 @@ namespace mu return iStat; } + //--------------------------------------------------------------------------------------------- + int ParserTester::TestOptimizer() + { + int iStat = 0; + mu::console() << _T("testing optimizer..."); + + // Test RemoveVar + Parser p; + try + { + p.DefineFun(_T("unoptimizable"), f1of1, false); + p.SetExpr(_T("unoptimizable(1)")); + p.Eval(); + + // test for #93 (https://github.com/beltoforion/muparser/issues/93) + // expected bytecode is: + // FUN, VAL, END + auto& bc = p.GetByteCode(); + const SToken* tok = bc.GetBase(); + if (tok->Cmd != cmFUNC) + { + mu::console() << _T("#93 an unoptimizable expression was optimized!") << endl; + iStat += 1; + } + } + catch (...) + { + iStat += 1; // this is not supposed to happen + } + + if (iStat == 0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + + return iStat; + } + //--------------------------------------------------------------------------------------------- int ParserTester::TestStrArg() { @@ -137,7 +176,7 @@ namespace mu mu::console() << _T("testing string arguments..."); // from oss-fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=23410 - iStat += ThrowTest(_T(R"(6 - 6 ? 4 : "", ? 4 : "", ? 4 : "")"), ecUNEXPECTED_STR, true); + iStat += ThrowTest(_T(R"(6 - 6 ? 4 : "", ? 4 : "", ? 4 : "")"), ecUNEXPECTED_STR, true); // variations: iStat += ThrowTest(_T(R"(avg(0?4:(""),1))"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(1 ? 4 : "")"), ecUNEXPECTED_STR); @@ -149,7 +188,7 @@ namespace mu // from oss-fuzz: https://oss-fuzz.com/testcase-detail/5106868061208576 iStat += ThrowTest(_T(R"("","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",8)"), ecSTR_RESULT); - + // derived from oss-fuzz: https://oss-fuzz.com/testcase-detail/5758791700971520 iStat += ThrowTest(_T("(\"\"), 7"), ecSTR_RESULT); iStat += ThrowTest(_T("((\"\")), 7"), ecSTR_RESULT); @@ -158,7 +197,7 @@ namespace mu //iStat += ThrowTest(_T("(\"\"),(\"\"), (3)"), ecSTR_RESULT); //iStat += ThrowTest(_T("(\"\"),(\"\"), 7"), ecSTR_RESULT); - + // variations: iStat += ThrowTest(_T(R"("","",9)"), ecSTR_RESULT); @@ -209,18 +248,18 @@ namespace mu // c: 3,3,3,3 // d: 5,4,3,2 EQN_TEST_BULK("a", 1, 1, 1, 1, false) - EQN_TEST_BULK("a", 1, 2, 3, 4, true) - EQN_TEST_BULK("b=a", 1, 2, 3, 4, true) - EQN_TEST_BULK("b=a, b*10", 10, 20, 30, 40, true) - EQN_TEST_BULK("b=a, b*10, a", 1, 2, 3, 4, true) - EQN_TEST_BULK("a+b", 3, 4, 5, 6, true) - EQN_TEST_BULK("c*(a+b)", 9, 12, 15, 18, true) + EQN_TEST_BULK("a", 1, 2, 3, 4, true) + EQN_TEST_BULK("b=a", 1, 2, 3, 4, true) + EQN_TEST_BULK("b=a, b*10", 10, 20, 30, 40, true) + EQN_TEST_BULK("b=a, b*10, a", 1, 2, 3, 4, true) + EQN_TEST_BULK("a+b", 3, 4, 5, 6, true) + EQN_TEST_BULK("c*(a+b)", 9, 12, 15, 18, true) #undef EQN_TEST_BULK - if (iStat == 0) - mu::console() << _T("passed") << endl; - else - mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + if (iStat == 0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } @@ -388,93 +427,93 @@ namespace mu // constant names PARSER_THROWCHECK(Const, false, _T("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), 1) - PARSER_THROWCHECK(Const, false, _T("0a"), 1) - PARSER_THROWCHECK(Const, false, _T("9a"), 1) - PARSER_THROWCHECK(Const, false, _T("+a"), 1) - PARSER_THROWCHECK(Const, false, _T("-a"), 1) - PARSER_THROWCHECK(Const, false, _T("a-"), 1) - PARSER_THROWCHECK(Const, false, _T("a*"), 1) - PARSER_THROWCHECK(Const, false, _T("a?"), 1) - PARSER_THROWCHECK(Const, true, _T("a"), 1) - PARSER_THROWCHECK(Const, true, _T("a_min"), 1) - PARSER_THROWCHECK(Const, true, _T("a_min0"), 1) - PARSER_THROWCHECK(Const, true, _T("a_min9"), 1) - - // variable names - value_type a; + PARSER_THROWCHECK(Const, false, _T("0a"), 1) + PARSER_THROWCHECK(Const, false, _T("9a"), 1) + PARSER_THROWCHECK(Const, false, _T("+a"), 1) + PARSER_THROWCHECK(Const, false, _T("-a"), 1) + PARSER_THROWCHECK(Const, false, _T("a-"), 1) + PARSER_THROWCHECK(Const, false, _T("a*"), 1) + PARSER_THROWCHECK(Const, false, _T("a?"), 1) + PARSER_THROWCHECK(Const, true, _T("a"), 1) + PARSER_THROWCHECK(Const, true, _T("a_min"), 1) + PARSER_THROWCHECK(Const, true, _T("a_min0"), 1) + PARSER_THROWCHECK(Const, true, _T("a_min9"), 1) + + // variable names + value_type a; p.ClearConst(); PARSER_THROWCHECK(Var, false, _T("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), &a); PARSER_THROWCHECK(Var, false, _T("123abc"), &a) - PARSER_THROWCHECK(Var, false, _T("9a"), &a) - PARSER_THROWCHECK(Var, false, _T("0a"), &a) - PARSER_THROWCHECK(Var, false, _T("+a"), &a) - PARSER_THROWCHECK(Var, false, _T("-a"), &a) - PARSER_THROWCHECK(Var, false, _T("?a"), &a) - PARSER_THROWCHECK(Var, false, _T("!a"), &a) - PARSER_THROWCHECK(Var, false, _T("a+"), &a) - PARSER_THROWCHECK(Var, false, _T("a-"), &a) - PARSER_THROWCHECK(Var, false, _T("a*"), &a) - PARSER_THROWCHECK(Var, false, _T("a?"), &a) - PARSER_THROWCHECK(Var, true, _T("a"), &a) - PARSER_THROWCHECK(Var, true, _T("a_min"), &a) - PARSER_THROWCHECK(Var, true, _T("a_min0"), &a) - PARSER_THROWCHECK(Var, true, _T("a_min9"), &a) - PARSER_THROWCHECK(Var, false, _T("a_min9"), 0) - - // Postfix operators - // fail - PARSER_THROWCHECK(PostfixOprt, false, _T("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), f1of1); + PARSER_THROWCHECK(Var, false, _T("9a"), &a) + PARSER_THROWCHECK(Var, false, _T("0a"), &a) + PARSER_THROWCHECK(Var, false, _T("+a"), &a) + PARSER_THROWCHECK(Var, false, _T("-a"), &a) + PARSER_THROWCHECK(Var, false, _T("?a"), &a) + PARSER_THROWCHECK(Var, false, _T("!a"), &a) + PARSER_THROWCHECK(Var, false, _T("a+"), &a) + PARSER_THROWCHECK(Var, false, _T("a-"), &a) + PARSER_THROWCHECK(Var, false, _T("a*"), &a) + PARSER_THROWCHECK(Var, false, _T("a?"), &a) + PARSER_THROWCHECK(Var, true, _T("a"), &a) + PARSER_THROWCHECK(Var, true, _T("a_min"), &a) + PARSER_THROWCHECK(Var, true, _T("a_min0"), &a) + PARSER_THROWCHECK(Var, true, _T("a_min9"), &a) + PARSER_THROWCHECK(Var, false, _T("a_min9"), 0) + + // Postfix operators + // fail + PARSER_THROWCHECK(PostfixOprt, false, _T("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), f1of1); PARSER_THROWCHECK(PostfixOprt, false, _T("(k"), f1of1) - PARSER_THROWCHECK(PostfixOprt, false, _T("9+"), f1of1) - PARSER_THROWCHECK(PostfixOprt, false, _T("+"), 0) - // pass - PARSER_THROWCHECK(PostfixOprt, true, _T("-a"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("?a"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("_"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("#"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("&&"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("||"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("&"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("|"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("++"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("--"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("?>"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1) - PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1) - - // Binary operator - // The following must fail with builtin operators activated - // p.EnableBuiltInOp(true); -> this is the default - p.ClearPostfixOprt(); + PARSER_THROWCHECK(PostfixOprt, false, _T("9+"), f1of1) + PARSER_THROWCHECK(PostfixOprt, false, _T("+"), 0) + // pass + PARSER_THROWCHECK(PostfixOprt, true, _T("-a"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("?a"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("_"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("#"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("&&"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("||"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("&"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("|"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("++"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("--"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("?>"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1) + PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1) + + // Binary operator + // The following must fail with builtin operators activated + // p.EnableBuiltInOp(true); -> this is the default + p.ClearPostfixOprt(); PARSER_THROWCHECK(Oprt, false, _T("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), f1of2); PARSER_THROWCHECK(Oprt, false, _T("+"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("^"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("&&"), f1of2) - PARSER_THROWCHECK(Oprt, false, _T("||"), f1of2) - - // without activated built in operators it should work - p.EnableBuiltInOprt(false); + PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("^"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("&&"), f1of2) + PARSER_THROWCHECK(Oprt, false, _T("||"), f1of2) + + // without activated built in operators it should work + p.EnableBuiltInOprt(false); PARSER_THROWCHECK(Oprt, true, _T("+"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("^"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("&&"), f1of2) - PARSER_THROWCHECK(Oprt, true, _T("||"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("^"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("&&"), f1of2) + PARSER_THROWCHECK(Oprt, true, _T("||"), f1of2) #undef PARSER_THROWCHECK - if (iStat == 0) - mu::console() << _T("passed") << endl; - else - mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; + if (iStat == 0) + mu::console() << _T("passed") << endl; + else + mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } @@ -993,7 +1032,7 @@ namespace mu iStat += ThrowTest(_T("1 : 2"), ecMISPLACED_COLON); iStat += ThrowTest(_T("(1) ? 1 : 2 : 3"), ecMISPLACED_COLON); iStat += ThrowTest(_T("(true) ? 1 : 2 : 3"), ecUNASSIGNABLE_TOKEN); - + // from oss-fzz.com: UNKNOWN READ; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22922#c1 iStat += ThrowTest(_T("1?2:0?(7:1)"), ecMISPLACED_COLON); @@ -1242,7 +1281,7 @@ namespace mu p.DefineFun(_T("strfun4"), StrFun4); p.DefineFun(_T("strfun5"), StrFun5); p.SetExpr(a_str); -// p.EnableDebugDump(1, 0); + // p.EnableDebugDump(1, 0); p.Eval(); } catch (ParserError& e) diff --git a/src/muParserTokenReader.cpp b/src/muParserTokenReader.cpp index 13f0798..312a0c5 100644 --- a/src/muParserTokenReader.cpp +++ b/src/muParserTokenReader.cpp @@ -5,7 +5,7 @@ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ - Copyright (C) 2004 - 2020 Ingo Berg + Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: