Tokenizer:simplifyMathFunctions: added support for log()-functions. Improved testcases and documentation. The function simplifyMathFunctions() returns now true in case a simplifcation is made. This function is called within a while loop to guarantee all simplifications are made.

This commit is contained in:
Martin Ettl 2013-10-03 20:52:07 +02:00
parent 548e2f3fbf
commit f8bd33f2bc
3 changed files with 205 additions and 10 deletions

View File

@ -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");
}

View File

@ -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'

View File

@ -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<<cos(0);\n"
" std::cout<<sinh(0);\n"
" std::cout<<cosh(0);\n"
" std::cout<<ln(1);\n"
" std::cout<<pow(sin(x),2)+pow(cos(x),2);\n"
" std::cout<<pow(sin(pow(sin(y),2)+pow(cos(y),2)),2)+pow(cos(pow(sin(y),2)+pow(cos(y),2)),2);\n"
" std::cout<<pow(sin(x),2.0)+pow(cos(x),2.0);\n"
" std::cout<<pow(sin(x*y+z),2.0)+pow(cos(x*y+z),2.0);\n"
" std::cout<<pow(sin(x*y+z),2)+pow(cos(x*y+z),2);\n"
@ -8868,6 +9022,7 @@ private:
" std::cout<<pow(cosh(x),2)-pow(sinh(x),2);\n"
" std::cout<<pow(cosh(x*y+z),2.0)-pow(sinh(x*y+z),2.0);\n"
" std::cout<<pow(cosh(x),2.0)-pow(sinh(x),2.0);\n"
" std::cout<<pow(cosh(pow(x,1)),2.0)-pow(sinh(pow(x,1)),2.0);\n"
"}";
const char expected1[] = "void foo ( ) {\n"
@ -8875,7 +9030,6 @@ private:
"std :: cout << 1 ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"std :: cout << 1 ;\n"
"std :: cout << 1 ;\n"
@ -8884,6 +9038,8 @@ private:
"std :: cout << 1 ;\n"
"std :: cout << 1 ;\n"
"std :: cout << 1 ;\n"
"std :: cout << 1 ;\n"
"std :: cout << -1 ;\n"
"std :: cout << -1 ;\n"
"std :: cout << -1 ;\n"
"std :: cout << -1 ;\n"