diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index a63f6609d..af25f5038 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2047,7 +2047,7 @@ bool Tokenizer::tokenize(std::istream &code, simplifyInitVar(); // Convert e.g. atol("0") into 0 - simplifyMathFunctions(); + while (simplifyMathFunctions()) {}; simplifyDoublePlusAndDoubleMinus(); @@ -2149,7 +2149,7 @@ bool Tokenizer::tokenizeCondition(const std::string &code) while (simplifyLogicalOperators()) { } // Convert e.g. atol("0") into 0 - simplifyMathFunctions(); + while (simplifyMathFunctions()) {}; simplifyDoublePlusAndDoubleMinus(); @@ -3612,6 +3612,8 @@ bool Tokenizer::simplifyTokenList() simplifyEmptyNamespaces(); + while (simplifyMathFunctions()) {}; + if (!validate()) return false; @@ -8328,14 +8330,17 @@ bool Tokenizer::isTwoNumber(const std::string &s) // islessgreater(), islessequal(), pow(), powf(), powl(), // div(),ldiv(),lldiv(), cbrt(), cbrtl(), cbtrf(), sqrt(), // sqrtf(), sqrtl(), exp(), expf(), expl(), exp2(), -// exp2f(), exp2l(), log2(), log2f(), log2l() +// exp2f(), exp2l(), log2(), log2f(), log2l(), log1p(), +// log1pf(), log1pl(), log10(), log10l(), log10f(), +// log(),logf(),logl(),logb(),logbf(),logbl() // in the tokenlist. // // Reference: // - http://www.cplusplus.com/reference/cmath/ // ------------------------------------------------------ -void Tokenizer::simplifyMathFunctions() +bool Tokenizer::simplifyMathFunctions() { + bool simplifcationMade = false; for (Token *tok = list.front(); tok; tok = tok->next()) { if (Token::Match(tok, "atol ( %str% )")) { //@todo Add support for atoll() if (tok->previous() && @@ -8353,6 +8358,7 @@ void Tokenizer::simplifyMathFunctions() tok->deleteNext(3); // Convert string into a number and insert into token list tok->str(MathLib::toString(MathLib::toLongNumber(strNumber))); + simplifcationMade = true; } else if (Token::Match(tok, "abs|fabs|labs|llabs ( %num% )")) { if (tok->previous() && Token::simpleMatch(tok->tokAt(-2), "std ::")) { @@ -8367,6 +8373,7 @@ void Tokenizer::simplifyMathFunctions() } tok->deleteNext(3); // delete e.g. abs ( 1 ) tok->str(strNumber); // insert result into token list + simplifcationMade = true; } else if (Token::Match(tok, "sqrt|sqrtf|sqrtl|cbrt|cbrtf|cbrtl ( %num% )")) { // Simplify: sqrt(0) = 0 and cbrt(0) == 0 // sqrt(1) = 1 and cbrt(1) == 1 @@ -8376,9 +8383,11 @@ void Tokenizer::simplifyMathFunctions() if (isZeroNumber(parameter)) { tok->deleteNext(3); // delete tokens tok->str("0"); // insert result into token list + simplifcationMade = true; } else if (isOneNumber(parameter)) { tok->deleteNext(3); // delete tokens tok->str("1"); // insert result into token list + simplifcationMade = true; } } else if (Token::Match(tok, "exp|expf|expl|exp2|exp2f|exp2l ( %num% )")) { // Simplify: exp[f|l](0) = 1 and exp2[f|l](0) = 1 @@ -8388,15 +8397,27 @@ void Tokenizer::simplifyMathFunctions() if (isZeroNumber(parameter)) { tok->deleteNext(3); // delete tokens tok->str("1"); // insert result into token list + simplifcationMade = true; } - } else if (Token::Match(tok, "log2|log2f|log2l ( %num% )")) { - // Simplify: log2[f|l](1) = 0 + } else if (Token::Match(tok, "log1p|log1pf|log1pl ( %num% )")) { + // Simplify: log1p[f|l](0) = 0 // get number string const std::string parameter(tok->tokAt(2)->str()); // is parameter 0 ? + if (isZeroNumber(parameter)) { + tok->deleteNext(3); // delete tokens + tok->str("0"); // insert result into token list + simplifcationMade = true; + } + } else if (Token::Match(tok, "log2|log2f|log2l|log|logf|logl|log10|log10f|log10l|logb|logbf|logbl ( %num% )")) { + // Simplify: log2[f|l](1) = 0 + // get number string + const std::string parameter(tok->tokAt(2)->str()); + // is parameter 1 ? if (isOneNumber(parameter)) { tok->deleteNext(3); // delete tokens tok->str("0"); // insert result into token list + simplifcationMade = true; } } else if (Token::Match(tok, "fmin|fminl|fminf ( %num% , %num% )")) { // @todo if one of the parameters is NaN the other is returned @@ -8409,9 +8430,11 @@ void Tokenizer::simplifyMathFunctions() if (!strLeftNumber.empty() && !strRightNumber.empty() && isLessEqual) { tok->deleteNext(5); // delete e.g. fmin ( -1.0, 1.0 ) tok->str(strLeftNumber); // insert e.g. -1.0 + simplifcationMade = true; } else { // case left > right ==> insert right tok->deleteNext(5); // delete e.g. fmin ( 1.0, 0.0 ) tok->str(strRightNumber); // insert e.g. 0.0 + simplifcationMade = true; } } else if (Token::Match(tok, "fmax|fmaxl|fmaxf ( %num% , %num% )")) { // @todo if one of the parameters is NaN the other is returned @@ -8424,9 +8447,11 @@ void Tokenizer::simplifyMathFunctions() if (!strLeftNumber.empty() && !strRightNumber.empty() && isLessEqual) { tok->deleteNext(5); // delete e.g. fmax ( -1.0, 1.0 ) tok->str(strRightNumber);// insert e.g. 1.0 + simplifcationMade = true; } else { // case left > right ==> insert left tok->deleteNext(5); // delete e.g. fmax ( 1.0, 0.0 ) tok->str(strLeftNumber); // insert e.g. 1.0 + simplifcationMade = true; } } else if (Token::Match(tok, "isgreater ( %num% , %num% )")) { // The isgreater(x,y) function is the same as calculating (x)>(y). @@ -8437,6 +8462,7 @@ void Tokenizer::simplifyMathFunctions() const bool isGreater = MathLib::isGreater(strLeftNumber, strRightNumber); // compare numbers tok->deleteNext(5); // delete tokens tok->str((isGreater == true) ? "true": "false"); // insert results + simplifcationMade = true; } } else if (Token::Match(tok, "isgreaterequal ( %num% , %num% )")) { // The isgreaterequal(x,y) function is the same as calculating (x)>=(y). @@ -8448,6 +8474,7 @@ void Tokenizer::simplifyMathFunctions() const bool isGreaterEqual = MathLib::isGreaterEqual(strLeftNumber, strRightNumber); // compare numbers tok->deleteNext(5); // delete tokens tok->str((isGreaterEqual == true) ? "true": "false"); // insert results + simplifcationMade = true; } } else if (Token::Match(tok, "isless ( %num% , %num% )")) { // Calling this function is the same as calculating (x)<(y). @@ -8459,6 +8486,7 @@ void Tokenizer::simplifyMathFunctions() const bool isLess = MathLib::isLess(strLeftNumber, strRightNumber); // compare numbers tok->deleteNext(5); // delete tokens tok->str((isLess == true) ? "true": "false"); // insert results + simplifcationMade = true; } } else if (Token::Match(tok, "islessequal ( %num% , %num% )")) { // Calling this function is the same as calculating (x)<=(y). @@ -8470,6 +8498,7 @@ void Tokenizer::simplifyMathFunctions() const bool isLessEqual = MathLib::isLessEqual(strLeftNumber, strRightNumber); // compare numbers tok->deleteNext(5); // delete tokens tok->str((isLessEqual == true) ? "true": "false"); // insert results + simplifcationMade = true; } } else if (Token::Match(tok, "islessgreater ( %num% , %num% )")) { // Calling this function is the same as calculating (x)<(y) || (x)>(y). @@ -8482,6 +8511,7 @@ void Tokenizer::simplifyMathFunctions() MathLib::isGreater(strLeftNumber, strRightNumber)); // compare numbers tok->deleteNext(5); // delete tokens tok->str((isLessOrGreater == true) ? "true": "false"); // insert results + simplifcationMade = true; } } else if (Token::Match(tok, "div|ldiv|lldiv ( %any% , %num% )")) { // Calling the function 'div(x,y)' is the same as calculating (x)/(y). In case y has the value 1 @@ -8492,6 +8522,7 @@ void Tokenizer::simplifyMathFunctions() if (isOneNumber(rightNumber)) { tok->deleteNext(5); // delete tokens tok->str(leftParameter); // insert simplified result + simplifcationMade = true; } } } else if (Token::Match(tok, "pow|powf|powl (")) { @@ -8503,9 +8534,11 @@ void Tokenizer::simplifyMathFunctions() if (isOneNumber(rightNumber)) { // case: x^(1) = x tok->deleteNext(5); // delete tokens tok->str(leftParameter); // insert simplified result + simplifcationMade = true; } else if (isZeroNumber(rightNumber)) { // case: x^(0) = 1 tok->deleteNext(5); // delete tokens tok->str("1"); // insert simplified result + simplifcationMade = true; } } } else if (tok && Token::Match(tok->tokAt(2), " %num% , %num% )")) { @@ -8521,17 +8554,22 @@ void Tokenizer::simplifyMathFunctions() if (isLeftNumberZero && !isRightNumberZero && MathLib::isPositive(rightNumber)) { // case: 0^(y) = 0 and y > 0 tok->deleteNext(5); // delete tokens tok->str("0"); // insert simplified result + simplifcationMade = true; } else if (isLeftNumberZero && isRightNumberZero) { // case: 0^0 = 1 tok->deleteNext(5); // delete tokens tok->str("1"); // insert simplified result + simplifcationMade = true; } else if (isLeftNumberOne) { // case 1^(y) = 1 tok->deleteNext(5); // delete tokens tok->str("1"); // insert simplified result + simplifcationMade = true; } } } } } + // returns true if a simplifcation was performed and false otherwise. + return simplifcationMade; } void Tokenizer::simplifyComma() @@ -10243,7 +10281,7 @@ void Tokenizer::simplifyMathExpressions() tok->str("1"); } - if (Token::Match(tok,"sin|sinh ( 0 )") || Token::simpleMatch(tok,"ln ( 1 )")) { + if (Token::Match(tok,"sin|sinh ( 0 )")) { tok->deleteNext(3); tok->str("0"); } diff --git a/lib/tokenize.h b/lib/tokenize.h index af5fe10dd..fabe31948 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -480,8 +480,9 @@ public: /** * Simplify e.g. 'atol("0")' into '0' + * @return returns true if simplifcations performed and false otherwise. */ - void simplifyMathFunctions(); + bool simplifyMathFunctions(); /** * Simplify e.g. 'sin(0)' into '0' diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 2e354b6fb..6816f605e 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -8294,6 +8294,8 @@ private: ASSERT_EQUALS(false, Tokenizer::isZeroNumber("1.0")); ASSERT_EQUALS(false, Tokenizer::isZeroNumber("+1.0")); ASSERT_EQUALS(false, Tokenizer::isZeroNumber("-1")); + ASSERT_EQUALS(false, Tokenizer::isZeroNumber("")); + ASSERT_EQUALS(false, Tokenizer::isZeroNumber("garbage")); } void isOneNumber() const { @@ -8308,6 +8310,8 @@ private: ASSERT_EQUALS(false, Tokenizer::isOneNumber("0.0")); ASSERT_EQUALS(false, Tokenizer::isOneNumber("+0.0")); ASSERT_EQUALS(false, Tokenizer::isOneNumber("-0")); + ASSERT_EQUALS(false, Tokenizer::isOneNumber("")); + ASSERT_EQUALS(false, Tokenizer::isOneNumber("garbage")); } void isTwoNumber() const { @@ -8322,10 +8326,160 @@ private: ASSERT_EQUALS(false, Tokenizer::isTwoNumber("0.0")); ASSERT_EQUALS(false, Tokenizer::isTwoNumber("+0.0")); ASSERT_EQUALS(false, Tokenizer::isTwoNumber("-0")); + ASSERT_EQUALS(false, Tokenizer::isTwoNumber("")); + ASSERT_EQUALS(false, Tokenizer::isTwoNumber("garbage")); } void simplifyMathFunctions() { //#5031 + // verify logb(), logbf(), logbl() - simplifcation + const char code_logb[] ="void f(int x) {\n" + " std::cout << logb(x);\n" // do not simplify + " std::cout << logb(10);\n" // do not simplify + " std::cout << logb(1L);\n" // simplify to 0 + "}"; + const char expected_logb[] = "void f ( int x ) {\n" + "std :: cout << logb ( x ) ;\n" + "std :: cout << logb ( 10 ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_logb, tokenizeAndStringify(code_logb)); + + const char code_logbf[] ="void f(float x) {\n" + " std::cout << logbf(x);\n" // do not simplify + " std::cout << logbf(10);\n" // do not simplify + " std::cout << logbf(1.0f);\n" // simplify to 0 + "}"; + const char expected_logbf[] = "void f ( float x ) {\n" + "std :: cout << logbf ( x ) ;\n" + "std :: cout << logbf ( 10 ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_logbf, tokenizeAndStringify(code_logbf)); + + const char code_logbl[] ="void f(long double x) {\n" + " std::cout << logbl(x);\n" // do not simplify + " std::cout << logbl(10.0d);\n" // do not simplify + " std::cout << logbl(1.0d);\n" // simplify to 0 + "}"; + const char expected_logbl[] = "void f ( long double x ) {\n" + "std :: cout << logbl ( x ) ;\n" + "std :: cout << logbl ( 10.0d ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_logbl, tokenizeAndStringify(code_logbl)); + + // verify log1p(), log1pf(), log1pl() - simplifcation + const char code_log1p[] ="void f(int x) {\n" + " std::cout << log1p(x);\n" // do not simplify + " std::cout << log1p(10);\n" // do not simplify + " std::cout << log1p(0L);\n" // simplify to 0 + "}"; + const char expected_log1p[] = "void f ( int x ) {\n" + "std :: cout << log1p ( x ) ;\n" + "std :: cout << log1p ( 10 ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_log1p, tokenizeAndStringify(code_log1p)); + + const char code_log1pf[] ="void f(float x) {\n" + " std::cout << log1pf(x);\n" // do not simplify + " std::cout << log1pf(10);\n" // do not simplify + " std::cout << log1pf(0.0f);\n" // simplify to 0 + "}"; + const char expected_log1pf[] = "void f ( float x ) {\n" + "std :: cout << log1pf ( x ) ;\n" + "std :: cout << log1pf ( 10 ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_log1pf, tokenizeAndStringify(code_log1pf)); + + const char code_log1pl[] ="void f(long double x) {\n" + " std::cout << log1pl(x);\n" // do not simplify + " std::cout << log1pl(10.0d);\n" // do not simplify + " std::cout << log1pl(0.0d);\n" // simplify to 0 + "}"; + const char expected_log1pl[] = "void f ( long double x ) {\n" + "std :: cout << log1pl ( x ) ;\n" + "std :: cout << log1pl ( 10.0d ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_log1pl, tokenizeAndStringify(code_log1pl)); + + // verify log10(), log10f(), log10l() - simplifcation + const char code_log10[] ="void f(int x) {\n" + " std::cout << log10(x);\n" // do not simplify + " std::cout << log10(10);\n" // do not simplify + " std::cout << log10(1L);\n" // simplify to 0 + "}"; + const char expected_log10[] = "void f ( int x ) {\n" + "std :: cout << log10 ( x ) ;\n" + "std :: cout << log10 ( 10 ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_log10, tokenizeAndStringify(code_log10)); + + const char code_log10f[] ="void f(float x) {\n" + " std::cout << log10f(x);\n" // do not simplify + " std::cout << log10f(10);\n" // do not simplify + " std::cout << log10f(1.0f);\n" // simplify to 0 + "}"; + const char expected_log10f[] = "void f ( float x ) {\n" + "std :: cout << log10f ( x ) ;\n" + "std :: cout << log10f ( 10 ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_log10f, tokenizeAndStringify(code_log10f)); + + const char code_log10l[] ="void f(long double x) {\n" + " std::cout << log10l(x);\n" // do not simplify + " std::cout << log10l(10.0d);\n" // do not simplify + " std::cout << log10l(1.0d);\n" // simplify to 0 + "}"; + const char expected_log10l[] = "void f ( long double x ) {\n" + "std :: cout << log10l ( x ) ;\n" + "std :: cout << log10l ( 10.0d ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_log10l, tokenizeAndStringify(code_log10l)); + + // verify log(), logf(), logl() - simplifcation + const char code_log[] ="void f(int x) {\n" + " std::cout << log(x);\n" // do not simplify + " std::cout << log(10);\n" // do not simplify + " std::cout << log(1L);\n" // simplify to 0 + "}"; + const char expected_log[] = "void f ( int x ) {\n" + "std :: cout << log ( x ) ;\n" + "std :: cout << log ( 10 ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_log, tokenizeAndStringify(code_log)); + + const char code_logf[] ="void f(float x) {\n" + " std::cout << logf(x);\n" // do not simplify + " std::cout << logf(10);\n" // do not simplify + " std::cout << logf(1.0f);\n" // simplify to 0 + "}"; + const char expected_logf[] = "void f ( float x ) {\n" + "std :: cout << logf ( x ) ;\n" + "std :: cout << logf ( 10 ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_logf, tokenizeAndStringify(code_logf)); + + const char code_logl[] ="void f(long double x) {\n" + " std::cout << logl(x);\n" // do not simplify + " std::cout << logl(10.0d);\n" // do not simplify + " std::cout << logl(1.0d);\n" // simplify to 0 + "}"; + const char expected_logl[] = "void f ( long double x ) {\n" + "std :: cout << logl ( x ) ;\n" + "std :: cout << logl ( 10.0d ) ;\n" + "std :: cout << 0 ;\n" + "}"; + ASSERT_EQUALS(expected_logl, tokenizeAndStringify(code_logl)); + // verify log2(), log2f(), log2l() - simplifcation const char code_log2[] ="void f(int x) {\n" " std::cout << log2(x);\n" // do not simplify @@ -8851,8 +9005,8 @@ private: " std::cout<