From 0747b55485ec396f90949e51e21811a990231a23 Mon Sep 17 00:00:00 2001 From: Alexander Mai Date: Mon, 24 Feb 2014 18:52:31 +0100 Subject: [PATCH] Fixed #5304 (Wrong simplification of numbers like 001E+07 to 1.0) --- lib/mathlib.cpp | 112 ++++++++++++++++++++++++++++-------------- test/testmathlib.cpp | 33 +++++++------ test/testtokenize.cpp | 108 ++++++++++++++++++++-------------------- 3 files changed, 147 insertions(+), 106 deletions(-) diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 6fb7d61d2..c10f02f01 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -103,46 +103,84 @@ template<> std::string MathLib::toString(double value) bool MathLib::isFloat(const std::string &s) { - // every number that contains a . is a float - if (s.find("." , 0) != std::string::npos) - return true; - // scientific notation (without dot!) - std::string::const_iterator it=s.begin(); - if (*it=='+' || *it=='-') { // mantissa sign char - ++it; - if (it == s.end()) - return false; - } - if (!std::isdigit(*it)) + if (s.empty()) return false; - ++it; - while (std::isdigit(*it)) { // number - ++it; - if (it == s.end()) + enum {START, BASE_PLUSMINUS, BASE_DIGITS1, LEADING_DECIMAL, TRAILING_DECIMAL, BASE_DIGITS2, E, MANTISSA_PLUSMINUS, MANTISSA_DIGITS, F} state = START; + for (std::string::const_iterator it = s.begin(); it != s.end(); it++) { + switch (state) { + case START: + if (*it=='+' || *it=='-') + state=BASE_PLUSMINUS; + else if (*it=='.') + state=LEADING_DECIMAL; + else if (std::isdigit(*it)) + state=BASE_DIGITS1; + else + return false; + break; + case BASE_PLUSMINUS: + if (*it=='.') + state=LEADING_DECIMAL; + else if (std::isdigit(*it)) + state=BASE_DIGITS1; + else if (*it=='e' || *it=='E') + state=E; + else + return false; + break; + case LEADING_DECIMAL: + if (std::isdigit(*it)) + state=BASE_DIGITS2; + break; + case BASE_DIGITS1: + if (*it=='e' || *it=='E') + state=E; + else if (*it=='.') + state=TRAILING_DECIMAL; + else if (!std::isdigit(*it)) + return false; + break; + case TRAILING_DECIMAL: + if (*it=='e' || *it=='E') + state=E; + else if (std::isdigit(*it)) + state=BASE_DIGITS2; + else + return false; + break; + case BASE_DIGITS2: + if (*it=='e' || *it=='E') + state=E; + else if (*it=='f' || *it=='F') + state=F; + else if (!std::isdigit(*it)) + return false; + break; + case E: + if (*it=='+' || *it=='-') + state=MANTISSA_PLUSMINUS; + else if (std::isdigit(*it)) + state=MANTISSA_DIGITS; + else + return false; + break; + case MANTISSA_PLUSMINUS: + if (!std::isdigit(*it)) + return false; + else + state=MANTISSA_DIGITS; + break; + case MANTISSA_DIGITS: + if (*it=='f' || *it=='F') + state=F; + else if (!std::isdigit(*it)) + return false; + break; + case F: return false; + } } - if (*it!='e' && *it!='E') - return false; - else - ++it; - if (it == s.end()) - return false; // incomplete exponent number - if (*it=='+' || *it=='-') { // exponent sign char - ++it; - if (it == s.end()) - return false; // incomplete exponent number - } - - while (std::isdigit(*it)) { // number - ++it; - if (it == s.end()) - return true; - } - if (it==s.end()) - return true; - if ((*it=='f' || *it=='F') && (it+1)==s.end()) // trailing 'f'/'F' to indicate a float literal (as opposed to a double literal) - return true; - return false; + return (state==BASE_DIGITS2 || state == MANTISSA_DIGITS || state == TRAILING_DECIMAL || state == F); } bool MathLib::isNegative(const std::string &s) diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 2e639443b..ea4983155 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -345,19 +345,18 @@ private: } void isfloat() const { - - TODO_ASSERT_EQUALS(false, true, MathLib::isFloat(".")); - TODO_ASSERT_EQUALS(false, true, MathLib::isFloat("...")); - TODO_ASSERT_EQUALS(false, true, MathLib::isFloat("+E.")); - TODO_ASSERT_EQUALS(false, true, MathLib::isFloat("+e.")); - TODO_ASSERT_EQUALS(false, true, MathLib::isFloat("-E.")); - TODO_ASSERT_EQUALS(false, true, MathLib::isFloat("-e.")); - TODO_ASSERT_EQUALS(false, true, MathLib::isFloat("-.")); - TODO_ASSERT_EQUALS(false, true, MathLib::isFloat("-.")); + ASSERT_EQUALS(false, MathLib::isFloat("")); + ASSERT_EQUALS(false, MathLib::isFloat(".")); + ASSERT_EQUALS(false, MathLib::isFloat("...")); + ASSERT_EQUALS(false, MathLib::isFloat("+E.")); + ASSERT_EQUALS(false, MathLib::isFloat("+e.")); + ASSERT_EQUALS(false, MathLib::isFloat("-E.")); + ASSERT_EQUALS(false, MathLib::isFloat("-e.")); + ASSERT_EQUALS(false, MathLib::isFloat("-.")); + ASSERT_EQUALS(false, MathLib::isFloat("-.")); ASSERT_EQUALS(false, MathLib::isFloat("-")); ASSERT_EQUALS(false, MathLib::isFloat("+")); ASSERT_EQUALS(false, MathLib::isFloat(" ")); - ASSERT_EQUALS(false, MathLib::isFloat("")); ASSERT_EQUALS(false, MathLib::isFloat("0")); ASSERT_EQUALS(false, MathLib::isFloat("0 ")); @@ -365,9 +364,9 @@ private: ASSERT_EQUALS(false, MathLib::isFloat(" 0")); ASSERT_EQUALS(true , MathLib::isFloat("0.")); - ASSERT_EQUALS(true , MathLib::isFloat("0. ")); - ASSERT_EQUALS(true , MathLib::isFloat(" 0. ")); - ASSERT_EQUALS(true , MathLib::isFloat(" 0.")); + ASSERT_EQUALS(false , MathLib::isFloat("0. ")); + ASSERT_EQUALS(false , MathLib::isFloat(" 0. ")); + ASSERT_EQUALS(false , MathLib::isFloat(" 0.")); ASSERT_EQUALS(true , MathLib::isFloat("0.0")); ASSERT_EQUALS(true , MathLib::isFloat("-0.")); @@ -393,14 +392,15 @@ private: ASSERT_EQUALS(true , MathLib::isFloat("+1E+1")); ASSERT_EQUALS(true , MathLib::isFloat("+1E+100")); ASSERT_EQUALS(true , MathLib::isFloat("+1E+100f")); + ASSERT_EQUALS(true , MathLib::isFloat("+1E+007")); // to be sure about #5485 ASSERT_EQUALS(true , MathLib::isFloat("+1E+001f")); ASSERT_EQUALS(false , MathLib::isFloat("+1E+001f2")); ASSERT_EQUALS(true , MathLib::isFloat("+1E+10000")); ASSERT_EQUALS(true , MathLib::isFloat("-1E+1")); ASSERT_EQUALS(true , MathLib::isFloat("-1E+10000")); - ASSERT_EQUALS(true , MathLib::isFloat(".1250E+04")); - ASSERT_EQUALS(true , MathLib::isFloat("-1E-1")); - ASSERT_EQUALS(true , MathLib::isFloat("-1E-10000")); + ASSERT_EQUALS(true , MathLib::isFloat(".1250E+04")); + ASSERT_EQUALS(true , MathLib::isFloat("-1E-1")); + ASSERT_EQUALS(true , MathLib::isFloat("-1E-10000")); ASSERT_EQUALS(true , MathLib::isFloat("+1.23e+01")); ASSERT_EQUALS(true , MathLib::isFloat("+1.23E+01")); @@ -409,6 +409,7 @@ private: ASSERT_EQUALS(true , MathLib::isFloat("0.00004")); ASSERT_EQUALS(true , MathLib::isFloat("2352.00001f")); ASSERT_EQUALS(true , MathLib::isFloat(".4")); + ASSERT_EQUALS(true , MathLib::isFloat(".3e2")); ASSERT_EQUALS(true , MathLib::isFloat("1.0E+1")); ASSERT_EQUALS(true , MathLib::isFloat("1.0E-1")); ASSERT_EQUALS(true , MathLib::isFloat("-1.0E+1")); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index cfc6519f1..3115b417c 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -8589,7 +8589,7 @@ private: const char code_erfcl[] ="void f(long double x) {\n" " std::cout << erfcl(x);\n" // do not simplify - " std::cout << erfcl(0.0d);\n" // simplify to 1 + " std::cout << erfcl(0.0f);\n" // simplify to 1 "}"; const char expected_erfcl[] = "void f ( long double x ) {\n" "std :: cout << erfcl ( x ) ;\n" @@ -8622,7 +8622,7 @@ private: const char code_cosl[] ="void f(long double x) {\n" " std::cout << cosl(x);\n" // do not simplify - " std::cout << cosl(0.0d);\n" // simplify to 1 + " std::cout << cosl(0.0f);\n" // simplify to 1 "}"; const char expected_cosl[] = "void f ( long double x ) {\n" "std :: cout << cosl ( x ) ;\n" @@ -8655,7 +8655,7 @@ private: const char code_coshl[] ="void f(long double x) {\n" " std::cout << coshl(x);\n" // do not simplify - " std::cout << coshl(0.0d);\n" // simplify to 1 + " std::cout << coshl(0.0f);\n" // simplify to 1 "}"; const char expected_coshl[] = "void f ( long double x ) {\n" "std :: cout << coshl ( x ) ;\n" @@ -8688,7 +8688,7 @@ private: const char code_acosl[] ="void f(long double x) {\n" " std::cout << acosl(x);\n" // do not simplify - " std::cout << acosl(1.0d);\n" // simplify to 0 + " std::cout << acosl(1.0f);\n" // simplify to 0 "}"; const char expected_acosl[] = "void f ( long double x ) {\n" "std :: cout << acosl ( x ) ;\n" @@ -8721,7 +8721,7 @@ private: const char code_acoshl[] ="void f(long double x) {\n" " std::cout << acoshl(x);\n" // do not simplify - " std::cout << acoshl(1.0d);\n" // simplify to 0 + " std::cout << acoshl(1.0f);\n" // simplify to 0 "}"; const char expected_acoshl[] = "void f ( long double x ) {\n" "std :: cout << acoshl ( x ) ;\n" @@ -8938,12 +8938,12 @@ private: const char code_erfl[] ="void f(long double x) {\n" " std::cout << erfl(x);\n" // do not simplify - " std::cout << erfl(10.0d);\n" // do not simplify - " std::cout << erfl(0.0d);\n" // simplify to 0 + " std::cout << erfl(10.0f);\n" // do not simplify + " std::cout << erfl(0.0f);\n" // simplify to 0 "}"; const char expected_erfl[] = "void f ( long double x ) {\n" "std :: cout << erfl ( x ) ;\n" - "std :: cout << erfl ( 10.0d ) ;\n" + "std :: cout << erfl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_erfl, tokenizeAndStringify(code_erfl)); @@ -8977,12 +8977,14 @@ private: const char code_atanhl[] ="void f(long double x) {\n" " std::cout << atanhl(x);\n" // do not simplify - " std::cout << atanhl(10.0d);\n" // do not simplify - " std::cout << atanhl(0.0d);\n" // simplify to 0 + " std::cout << atanhl(10.0f);\n" // do not simplify + " std::cout << atanhl(0.0d);\n" // do not simplify - invalid number! + " std::cout << atanhl(0.0f);\n" // simplify to 0 "}"; const char expected_atanhl[] = "void f ( long double x ) {\n" "std :: cout << atanhl ( x ) ;\n" - "std :: cout << atanhl ( 10.0d ) ;\n" + "std :: cout << atanhl ( 10.0f ) ;\n" + "std :: cout << atanhl ( 0.0d ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_atanhl, tokenizeAndStringify(code_atanhl)); @@ -9016,12 +9018,12 @@ private: const char code_atanl[] ="void f(long double x) {\n" " std::cout << atanl(x);\n" // do not simplify - " std::cout << atanl(10.0d);\n" // do not simplify - " std::cout << atanl(0.0d);\n" // simplify to 0 + " std::cout << atanl(10.0f);\n" // do not simplify + " std::cout << atanl(0.0f);\n" // simplify to 0 "}"; const char expected_atanl[] = "void f ( long double x ) {\n" "std :: cout << atanl ( x ) ;\n" - "std :: cout << atanl ( 10.0d ) ;\n" + "std :: cout << atanl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_atanl, tokenizeAndStringify(code_atanl)); @@ -9089,12 +9091,12 @@ private: const char code_tanhl[] ="void f(long double x) {\n" " std::cout << tanhl(x);\n" // do not simplify - " std::cout << tanhl(10.0d);\n" // do not simplify - " std::cout << tanhl(0.0d);\n" // simplify to 0 + " std::cout << tanhl(10.0f);\n" // do not simplify + " std::cout << tanhl(0.0f);\n" // simplify to 0 "}"; const char expected_tanhl[] = "void f ( long double x ) {\n" "std :: cout << tanhl ( x ) ;\n" - "std :: cout << tanhl ( 10.0d ) ;\n" + "std :: cout << tanhl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_tanhl, tokenizeAndStringify(code_tanhl)); @@ -9128,12 +9130,12 @@ private: const char code_tanl[] ="void f(long double x) {\n" " std::cout << tanl(x);\n" // do not simplify - " std::cout << tanl(10.0d);\n" // do not simplify - " std::cout << tanl(0.0d);\n" // simplify to 0 + " std::cout << tanl(10.0f);\n" // do not simplify + " std::cout << tanl(0.0f);\n" // simplify to 0 "}"; const char expected_tanl[] = "void f ( long double x ) {\n" "std :: cout << tanl ( x ) ;\n" - "std :: cout << tanl ( 10.0d ) ;\n" + "std :: cout << tanl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_tanl, tokenizeAndStringify(code_tanl)); @@ -9167,12 +9169,12 @@ private: const char code_expm1l[] ="void f(long double x) {\n" " std::cout << expm1l(x);\n" // do not simplify - " std::cout << expm1l(10.0d);\n" // do not simplify - " std::cout << expm1l(0.0d);\n" // simplify to 0 + " std::cout << expm1l(10.0f);\n" // do not simplify + " std::cout << expm1l(0.0f);\n" // simplify to 0 "}"; const char expected_expm1l[] = "void f ( long double x ) {\n" "std :: cout << expm1l ( x ) ;\n" - "std :: cout << expm1l ( 10.0d ) ;\n" + "std :: cout << expm1l ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_expm1l, tokenizeAndStringify(code_expm1l)); @@ -9206,12 +9208,12 @@ private: const char code_asinhl[] ="void f(long double x) {\n" " std::cout << asinhl(x);\n" // do not simplify - " std::cout << asinhl(10.0d);\n" // do not simplify - " std::cout << asinhl(0.0d);\n" // simplify to 0 + " std::cout << asinhl(10.0f);\n" // do not simplify + " std::cout << asinhl(0.0f);\n" // simplify to 0 "}"; const char expected_asinhl[] = "void f ( long double x ) {\n" "std :: cout << asinhl ( x ) ;\n" - "std :: cout << asinhl ( 10.0d ) ;\n" + "std :: cout << asinhl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_asinhl, tokenizeAndStringify(code_asinhl)); @@ -9245,12 +9247,12 @@ private: const char code_asinl[] ="void f(long double x) {\n" " std::cout << asinl(x);\n" // do not simplify - " std::cout << asinl(10.0d);\n" // do not simplify - " std::cout << asinl(0.0d);\n" // simplify to 0 + " std::cout << asinl(10.0f);\n" // do not simplify + " std::cout << asinl(0.0f);\n" // simplify to 0 "}"; const char expected_asinl[] = "void f ( long double x ) {\n" "std :: cout << asinl ( x ) ;\n" - "std :: cout << asinl ( 10.0d ) ;\n" + "std :: cout << asinl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_asinl, tokenizeAndStringify(code_asinl)); @@ -9284,12 +9286,12 @@ private: const char code_sinhl[] ="void f(long double x) {\n" " std::cout << sinhl(x);\n" // do not simplify - " std::cout << sinhl(10.0d);\n" // do not simplify - " std::cout << sinhl(0.0d);\n" // simplify to 0 + " std::cout << sinhl(10.0f);\n" // do not simplify + " std::cout << sinhl(0.0f);\n" // simplify to 0 "}"; const char expected_sinhl[] = "void f ( long double x ) {\n" "std :: cout << sinhl ( x ) ;\n" - "std :: cout << sinhl ( 10.0d ) ;\n" + "std :: cout << sinhl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_sinhl, tokenizeAndStringify(code_sinhl)); @@ -9323,12 +9325,12 @@ private: const char code_sinl[] ="void f(long double x) {\n" " std::cout << sinl(x);\n" // do not simplify - " std::cout << sinl(10.0d);\n" // do not simplify - " std::cout << sinl(0.0d);\n" // simplify to 0 + " std::cout << sinl(10.0f);\n" // do not simplify + " std::cout << sinl(0.0f);\n" // simplify to 0 "}"; const char expected_sinl[] = "void f ( long double x ) {\n" "std :: cout << sinl ( x ) ;\n" - "std :: cout << sinl ( 10.0d ) ;\n" + "std :: cout << sinl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_sinl, tokenizeAndStringify(code_sinl)); @@ -9362,12 +9364,12 @@ private: const char code_ilogbl[] ="void f(long double x) {\n" " std::cout << ilogbl(x);\n" // do not simplify - " std::cout << ilogbl(10.0d);\n" // do not simplify - " std::cout << ilogbl(1.0d);\n" // simplify to 0 + " std::cout << ilogbl(10.0f);\n" // do not simplify + " std::cout << ilogbl(1.0f);\n" // simplify to 0 "}"; const char expected_ilogbl[] = "void f ( long double x ) {\n" "std :: cout << ilogbl ( x ) ;\n" - "std :: cout << ilogbl ( 10.0d ) ;\n" + "std :: cout << ilogbl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_ilogbl, tokenizeAndStringify(code_ilogbl)); @@ -9401,12 +9403,12 @@ private: 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 + " std::cout << logbl(10.0f);\n" // do not simplify + " std::cout << logbl(1.0f);\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 << logbl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_logbl, tokenizeAndStringify(code_logbl)); @@ -9440,12 +9442,12 @@ private: 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 + " std::cout << log1pl(10.0f);\n" // do not simplify + " std::cout << log1pl(0.0f);\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 << log1pl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_log1pl, tokenizeAndStringify(code_log1pl)); @@ -9479,12 +9481,12 @@ private: 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 + " std::cout << log10l(10.0f);\n" // do not simplify + " std::cout << log10l(1.0f);\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 << log10l ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_log10l, tokenizeAndStringify(code_log10l)); @@ -9518,12 +9520,12 @@ private: 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 + " std::cout << logl(10.0f);\n" // do not simplify + " std::cout << logl(1.0f);\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 << logl ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_logl, tokenizeAndStringify(code_logl)); @@ -9557,12 +9559,12 @@ private: 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 + " std::cout << log2l(10.0f);\n" // do not simplify + " std::cout << log2l(1.0f);\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 << log2l ( 10.0f ) ;\n" "std :: cout << 0 ;\n" "}"; ASSERT_EQUALS(expected_log2l, tokenizeAndStringify(code_log2l));