From fa5ee8fd131ac92272bb00c80f97cde7ac0f6970 Mon Sep 17 00:00:00 2001 From: Martin Ettl Date: Tue, 1 Oct 2013 20:30:59 +0200 Subject: [PATCH] Tokenizer: simplifyMathFunctions: added more simplifications for exp(), exp2() and log2() functions. --- lib/tokenize.cpp | 29 +++++++---- lib/tokenize.h | 14 +++++ test/testtokenize.cpp | 117 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 147 insertions(+), 13 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9ad16a87a..aa170929e 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8272,27 +8272,26 @@ void Tokenizer::cppcheckError(const Token *tok) const "Analysis failed. If the code is valid then please report this failure."); } // ------------------------------------------------------------------------ -// Helper function to check wether number is zero (0,0.0 or 0E+0) or not? +// Helper function to check wether number is zero (0 or 0.0 or 0E+0) or not? // @param s --> a string to check // @return true in case s is zero and false otherwise. // ------------------------------------------------------------------------ -static bool isZeroNumber(const std::string &s) +bool Tokenizer::isZeroNumber(const std::string &s) { - const bool isPositive = MathLib::isPositive(s); const bool isInteger = MathLib::isInt(s); const bool isFloat = MathLib::isFloat(s); - const bool isZeroValue = ((isPositive && isInteger && (MathLib::toLongNumber(s) == 0L)) // case: integer number - || (isPositive && isFloat && MathLib::toString(MathLib::toDoubleNumber(s)) == "0.0")); // case: float number + const bool isZeroValue = ((isInteger && (MathLib::toLongNumber(s) == 0L)) // case: integer number + || (isFloat && MathLib::toString(MathLib::toDoubleNumber(s)) == "0.0")); // case: float number return isZeroValue; } // ------------------------------------------------------------------------ -// Helper function to check wether number is one (1,0.1 or 1E+0) or not? +// Helper function to check wether number is one (1 or 0.1E+1 or 1E+0) or not? // @param s --> a string to check // @return true in case s is zero and false otherwise. // ------------------------------------------------------------------------ -static bool isOneNumber(const std::string &s) +bool Tokenizer::isOneNumber(const std::string &s) { const bool isPositive = MathLib::isPositive(s); const bool isInteger = MathLib::isInt(s); @@ -8310,7 +8309,8 @@ static bool isOneNumber(const std::string &s) // fmaxf(), isgreater(), isgreaterequal(), isless() // islessgreater(), islessequal(), pow(), powf(), powl(), // div(),ldiv(),lldiv(), cbrt(), cbrtl(), cbtrf(), sqrt(), -// sqrtf(), sqrtl(), exp(), expf(), expl() +// sqrtf(), sqrtl(), exp(), expf(), expl(), exp2(), +// exp2f(), exp2l(), log2(), log2f(), log2l() // in the tokenlist. // // Reference: @@ -8362,8 +8362,8 @@ void Tokenizer::simplifyMathFunctions() tok->deleteNext(3); // delete tokens tok->str("1"); // insert result into token list } - } else if (Token::Match(tok, "exp|expf|expl ( %num% )")) { - // Simplify: exp(0) = 1 + } else if (Token::Match(tok, "exp|expf|expl|exp2|exp2f|exp2l ( %num% )")) { + // Simplify: exp[f|l](0) = 1 and exp2[f|l](0) = 1 // get number string const std::string parameter(tok->tokAt(2)->str()); // is parameter 0 ? @@ -8371,6 +8371,15 @@ void Tokenizer::simplifyMathFunctions() tok->deleteNext(3); // delete tokens tok->str("1"); // insert result into token list } + } else if (Token::Match(tok, "log2|log2f|log2l ( %num% )")) { + // Simplify: log2[f|l](1) = 0 + // get number string + const std::string parameter(tok->tokAt(2)->str()); + // is parameter 0 ? + if (isOneNumber(parameter)) { + tok->deleteNext(3); // delete tokens + tok->str("0"); // insert result into token list + } } else if (Token::Match(tok, "fmin|fminl|fminf ( %num% , %num% )")) { // @todo if one of the parameters is NaN the other is returned // e.g. printf ("fmin (NaN, -1.0) = %f\n", fmin(NaN,-1.0)); diff --git a/lib/tokenize.h b/lib/tokenize.h index 43b4dee49..a59efccd3 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -748,6 +748,20 @@ public: */ static Token *copyTokens(Token *dest, const Token *first, const Token *last, bool one_line = true); + /** + * Helper function to check wether number is zero (0 or 0.0 or 0E+0) or not? + * @param s --> a string to check + * @return true in case s is zero and false otherwise. + */ + static bool isZeroNumber(const std::string &s); + + /** + * Helper function to check wether number is one (1 or 0.1E+1 or 1E+0) or not? + * @param s --> a string to check + * @return true in case s is zero and false otherwise. + */ + static bool isOneNumber(const std::string &s); + private: /** Disable copy constructor, no implementation */ Tokenizer(const Tokenizer &); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index c43f43313..fb68cd983 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -309,6 +309,9 @@ private: TEST_CASE(doublesharp); + TEST_CASE(isZeroNumber); + TEST_CASE(isOneNumber); + TEST_CASE(macrodoublesharp); TEST_CASE(simplifyFunctionParameters); @@ -8278,13 +8281,121 @@ private: ASSERT_EQUALS(expected, tokenizeAndStringify(code, true, true, Settings::Win32W)); } + void isZeroNumber() const { + ASSERT_EQUALS(true, Tokenizer::isZeroNumber("0.0")); + ASSERT_EQUALS(true, Tokenizer::isZeroNumber("+0.0")); + ASSERT_EQUALS(true, Tokenizer::isZeroNumber("-0.0")); + ASSERT_EQUALS(true, Tokenizer::isZeroNumber("+0L")); + ASSERT_EQUALS(true, Tokenizer::isZeroNumber("+0")); + ASSERT_EQUALS(true, Tokenizer::isZeroNumber("-0")); + ASSERT_EQUALS(true, Tokenizer::isZeroNumber("-0E+0")); + + ASSERT_EQUALS(false, Tokenizer::isZeroNumber("1.0")); + ASSERT_EQUALS(false, Tokenizer::isZeroNumber("+1.0")); + ASSERT_EQUALS(false, Tokenizer::isZeroNumber("-1")); + } + + void isOneNumber() const { + ASSERT_EQUALS(true, Tokenizer::isOneNumber("1.0")); + ASSERT_EQUALS(true, Tokenizer::isOneNumber("+1.0")); + ASSERT_EQUALS(true, Tokenizer::isOneNumber("1.0e+0")); + ASSERT_EQUALS(true, Tokenizer::isOneNumber("+1L")); + ASSERT_EQUALS(true, Tokenizer::isOneNumber("+1")); + ASSERT_EQUALS(true, Tokenizer::isOneNumber("1")); + ASSERT_EQUALS(true, Tokenizer::isOneNumber("+1E+0")); + + ASSERT_EQUALS(false, Tokenizer::isOneNumber("0.0")); + ASSERT_EQUALS(false, Tokenizer::isOneNumber("+0.0")); + ASSERT_EQUALS(false, Tokenizer::isOneNumber("-0")); + } + void simplifyMathFunctions() { //#5031 + // verify log2(), log2f(), log2l() - simplifcation + const char code_log2[] ="void f(int x) {\n" + " std::cout << log2(x);\n" // do not simplify + " std::cout << log2(10);\n" // do not simplify + " std::cout << log2(1L);\n" // simplify to 0 + "}"; + const char expected_log2[] = "void f ( int x ) {\n" + "std :: cout << log2 ( x ) ;\n" + "std :: cout << log2 ( 10 ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_log2, tokenizeAndStringify(code_log2)); + + const char code_log2f[] ="void f(float x) {\n" + " std::cout << log2f(x);\n" // do not simplify + " std::cout << log2f(10);\n" // do not simplify + " std::cout << log2f(1.0f);\n" // simplify to 0 + "}"; + const char expected_log2f[] = "void f ( float x ) {\n" + "std :: cout << log2f ( x ) ;\n" + "std :: cout << log2f ( 10 ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_log2f, tokenizeAndStringify(code_log2f)); + + const char code_log2l[] ="void f(long double x) {\n" + " std::cout << log2l(x);\n" // do not simplify + " std::cout << log2l(10.0d);\n" // do not simplify + " std::cout << log2l(1.0d);\n" // simplify to 0 + "}"; + const char expected_log2l[] = "void f ( long double x ) {\n" + "std :: cout << log2l ( x ) ;\n" + "std :: cout << log2l ( 10.0d ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_log2l, tokenizeAndStringify(code_log2l)); + + // verify exp2(), exp2f(), exp2l() - simplifcation + const char code_exp2[] ="void f(int x) {\n" + " std::cout << exp2(x);\n" // do not simplify + " std::cout << exp2(-1);\n" // do not simplify + " std::cout << exp2(0L);\n" // simplify to 0 + " std::cout << exp2(1L);\n" // do not simplify + "}"; + const char expected_exp2[] = "void f ( int x ) {\n" + "std :: cout << exp2 ( x ) ;\n" + "std :: cout << exp2 ( -1 ) ;\n" + "std :: cout << 1 ;\n" + "std :: cout << exp2 ( 1L ) ;\n" + "}"; + ASSERT_EQUALS(expected_exp2, tokenizeAndStringify(code_exp2)); + + const char code_exp2f[] ="void f(float x) {\n" + " std::cout << exp2f(x);\n" // do not simplify + " std::cout << exp2f(-1.0);\n" // do not simplify + " std::cout << exp2f(0.0);\n" // simplify to 1 + " std::cout << exp2f(1.0);\n" // do not simplify + "}"; + const char expected_exp2f[] = "void f ( float x ) {\n" + "std :: cout << exp2f ( x ) ;\n" + "std :: cout << exp2f ( -1.0 ) ;\n" + "std :: cout << 1 ;\n" + "std :: cout << exp2f ( 1.0 ) ;\n" + "}"; + ASSERT_EQUALS(expected_exp2f, tokenizeAndStringify(code_exp2f)); + + const char code_exp2l[] ="void f(long double x) {\n" + " std::cout << exp2l(x);\n" // do not simplify + " std::cout << exp2l(-1.0);\n" // do not simplify + " std::cout << exp2l(0.0);\n" // simplify to 1 + " std::cout << exp2l(1.0);\n" // do not simplify + "}"; + const char expected_exp2l[] = "void f ( long double x ) {\n" + "std :: cout << exp2l ( x ) ;\n" + "std :: cout << exp2l ( -1.0 ) ;\n" + "std :: cout << 1 ;\n" + "std :: cout << exp2l ( 1.0 ) ;\n" + "}"; + ASSERT_EQUALS(expected_exp2l, tokenizeAndStringify(code_exp2l)); + // verify exp(), expf(), expl() - simplifcation const char code_exp[] ="void f(int x) {\n" " std::cout << exp(x);\n" // do not simplify " std::cout << exp(-1);\n" // do not simplify - " std::cout << exp(0L);\n" // simplify to 0 + " std::cout << exp(0L);\n" // simplify to 1 " std::cout << exp(1L);\n" // do not simplify "}"; const char expected_exp[] = "void f ( int x ) {\n" @@ -8298,7 +8409,7 @@ private: const char code_expf[] ="void f(float x) {\n" " std::cout << expf(x);\n" // do not simplify " std::cout << expf(-1.0);\n" // do not simplify - " std::cout << expf(0.0);\n" // simplify to 0 + " std::cout << expf(0.0);\n" // simplify to 1 " std::cout << expf(1.0);\n" // do not simplify "}"; const char expected_expf[] = "void f ( float x ) {\n" @@ -8312,7 +8423,7 @@ private: const char code_expl[] ="void f(long double x) {\n" " std::cout << expl(x);\n" // do not simplify " std::cout << expl(-1.0);\n" // do not simplify - " std::cout << expl(0.0);\n" // simplify to 0 + " std::cout << expl(0.0);\n" // simplify to 1 " std::cout << expl(1.0);\n" // do not simplify "}"; const char expected_expl[] = "void f ( long double x ) {\n"