From bbec54db8e04329693ce2e798d0d8f7d7e4d6e83 Mon Sep 17 00:00:00 2001 From: Alexander Mai Date: Sun, 26 Jul 2015 08:06:56 +0200 Subject: [PATCH] Implement MathLib::isFloatHex to detect C99 hexadecimal floating pointer literals. Rename MathLib::isHex to MathLib::isIntHex --- lib/mathlib.cpp | 88 ++++++++++++++++++--- lib/mathlib.h | 5 +- lib/tokenlist.cpp | 4 +- test/testmathlib.cpp | 178 ++++++++++++++++++++++++------------------- 4 files changed, 183 insertions(+), 92 deletions(-) diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 960096072..979fdbf46 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -262,7 +262,7 @@ MathLib::value MathLib::value::add(int v) const MathLib::biguint MathLib::toULongNumber(const std::string & str) { // hexadecimal numbers: - if (isHex(str)) { + if (isIntHex(str)) { if (str[0] == '-') { biguint ret = 0; std::istringstream istr(str); @@ -316,7 +316,7 @@ MathLib::biguint MathLib::toULongNumber(const std::string & str) MathLib::bigint MathLib::toLongNumber(const std::string & str) { // hexadecimal numbers: - if (isHex(str)) { + if (isIntHex(str)) { if (str[0] == '-') { bigint ret = 0; std::istringstream istr(str); @@ -372,7 +372,7 @@ MathLib::bigint MathLib::toLongNumber(const std::string & str) double MathLib::toDoubleNumber(const std::string &str) { - if (isHex(str)) + if (isIntHex(str)) return static_cast(toLongNumber(str)); // nullcheck else if (isNullValue(str)) @@ -555,14 +555,14 @@ bool MathLib::isOct(const std::string& s) if (isOctalDigit(*it)) state = DIGITS; else - return isValidSuffix(it,s.end()); + return isValidIntegerSuffix(it,s.end()); break; } } return state == DIGITS; } -bool MathLib::isHex(const std::string& s) +bool MathLib::isIntHex(const std::string& s) { enum Status { START, PLUSMINUS, HEX_PREFIX, DIGIT, DIGITS @@ -599,14 +599,82 @@ bool MathLib::isHex(const std::string& s) if (isxdigit(*it)) state = DIGITS; else - return isValidSuffix(it,s.end()); + return isValidIntegerSuffix(it,s.end()); break; } } return state == DIGITS; } -bool MathLib::isValidSuffix(std::string::const_iterator it, std::string::const_iterator end) +bool MathLib::isFloatHex(const std::string& s) +{ + enum Status { + START, PLUSMINUS, HEX_PREFIX, WHOLE_NUMBER_DIGIT, WHOLE_NUMBER_DIGITS, FRACTION, EXPONENT_DIGIT, EXPONENT_DIGITS + } state = START; + for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { + switch (state) { + case START: + if (*it == '+' || *it == '-') + state = PLUSMINUS; + else if (*it == '0') + state = HEX_PREFIX; + else + return false; + break; + case PLUSMINUS: + if (*it == '0') + state = HEX_PREFIX; + else + return false; + break; + case HEX_PREFIX: + if (*it == 'x' || *it == 'X') + state = WHOLE_NUMBER_DIGIT; + else + return false; + break; + case WHOLE_NUMBER_DIGIT: + if (isxdigit(*it)) + state = WHOLE_NUMBER_DIGITS; + else + return false; + break; + case WHOLE_NUMBER_DIGITS: + if (isxdigit(*it)) + state = WHOLE_NUMBER_DIGITS; + else if (*it=='.') + state = FRACTION; + else if (*it=='p' || *it=='P') + state = EXPONENT_DIGIT; + else + return false; + break; + case FRACTION: + if (isxdigit(*it)) + state = FRACTION; + else if (*it=='p' || *it=='P') + state = EXPONENT_DIGIT; + break; + case EXPONENT_DIGIT: + if (isxdigit(*it)) + state = EXPONENT_DIGITS; + else if (*it=='+' || *it=='-') + state = EXPONENT_DIGITS; + else + return false; + break; + case EXPONENT_DIGITS: + if (isxdigit(*it)) + state = EXPONENT_DIGITS; + else + return *it=='f'||*it=='F'||*it=='l'||*it=='L'; + break; + } + } + return state==EXPONENT_DIGITS; +} + +bool MathLib::isValidIntegerSuffix(std::string::const_iterator it, std::string::const_iterator end) { enum {START, SUFFIX_U, SUFFIX_UL, SUFFIX_ULL, SUFFIX_L, SUFFIX_LU, SUFFIX_LL, SUFFIX_LLU, SUFFIX_I, SUFFIX_I6, SUFFIX_I64} state = START; for (; it != end; ++it) { @@ -721,7 +789,7 @@ bool MathLib::isBin(const std::string& s) if (*it == '0' || *it == '1') state = DIGITS; else - return isValidSuffix(it,s.end()); + return isValidIntegerSuffix(it,s.end()); break; } } @@ -753,7 +821,7 @@ bool MathLib::isDec(const std::string & s) if (isdigit(*it)) state = DIGIT; else - return isValidSuffix(it,s.end()); + return isValidIntegerSuffix(it,s.end()); break; } } @@ -762,7 +830,7 @@ bool MathLib::isDec(const std::string & s) bool MathLib::isInt(const std::string & s) { - return isDec(s) || isHex(s) || isOct(s) || isBin(s); + return isDec(s) || isIntHex(s) || isOct(s) || isBin(s); } static std::string intsuffix(const std::string & first, const std::string & second) diff --git a/lib/mathlib.h b/lib/mathlib.h index e5e274b2f..f571b4d76 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -80,11 +80,12 @@ public: static bool isNegative(const std::string &str); static bool isPositive(const std::string &str); static bool isDec(const std::string & str); - static bool isHex(const std::string& str); + static bool isFloatHex(const std::string& str); + static bool isIntHex(const std::string& str); static bool isOct(const std::string& str); static bool isBin(const std::string& str); - static bool isValidSuffix(std::string::const_iterator it, std::string::const_iterator end); + static bool isValidIntegerSuffix(std::string::const_iterator it, std::string::const_iterator end); static std::string add(const std::string & first, const std::string & second); static std::string subtract(const std::string & first, const std::string & second); diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 33d003678..248694435 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -130,7 +130,7 @@ void TokenList::addtoken(const std::string & str, const unsigned int lineno, con // Replace hexadecimal value with decimal std::string str2; - if (MathLib::isHex(str) || MathLib::isOct(str) || MathLib::isBin(str)) { + if (MathLib::isIntHex(str) || MathLib::isOct(str) || MathLib::isBin(str)) { std::ostringstream str2stream; str2stream << MathLib::toULongNumber(str); str2 = str2stream.str(); @@ -305,7 +305,7 @@ bool TokenList::createTokens(std::istream &code, const std::string& file0) std::isdigit((unsigned char)CurrentToken[0]) && (CurrentToken.back() == 'e' || CurrentToken.back() == 'E') && - !MathLib::isHex(CurrentToken)) { + !MathLib::isIntHex(CurrentToken)) { // Don't separate doubles "4.2e+10" } else if (CurrentToken.empty() && ch == '.' && std::isdigit((unsigned char)code.peek())) { // tokenize .125 into 0.125 diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 9a4a01aeb..4a855c5cb 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -32,8 +32,9 @@ private: TEST_CASE(isbin); TEST_CASE(isdec); TEST_CASE(isoct); - TEST_CASE(ishex); - TEST_CASE(isValidSuffix); + TEST_CASE(isfloathex); + TEST_CASE(isinthex); + TEST_CASE(isValidIntegerSuffix); TEST_CASE(isnegative); TEST_CASE(ispositive); TEST_CASE(isfloat); @@ -552,136 +553,157 @@ private: ASSERT_EQUALS(false, MathLib::isOct("+042LUL+0")); } - void ishex() const { + void isfloathex() const { + // hex number syntax: [sign]0x[hexnumbers][suffix] + ASSERT_EQUALS(false, MathLib::isFloatHex("")); + ASSERT_EQUALS(true, MathLib::isFloatHex("0x1.999999999999ap-4")); + ASSERT_EQUALS(true, MathLib::isFloatHex("0x0.3p10")); + ASSERT_EQUALS(true, MathLib::isFloatHex("0x1.fp3")); + ASSERT_EQUALS(true, MathLib::isFloatHex("0x1P-1")); + ASSERT_EQUALS(true, MathLib::isFloatHex("0xcc.ccccccccccdp-11")); + ASSERT_EQUALS(true, MathLib::isFloatHex("0x3.243F6A88p+03")); + + ASSERT_EQUALS(false, MathLib::isFloatHex("0")); + ASSERT_EQUALS(false, MathLib::isFloatHex("0x")); + ASSERT_EQUALS(false, MathLib::isFloatHex("0xa")); + ASSERT_EQUALS(false, MathLib::isFloatHex("+0x")); + ASSERT_EQUALS(false, MathLib::isFloatHex("-0x")); + ASSERT_EQUALS(false, MathLib::isFloatHex("0x")); + ASSERT_EQUALS(false, MathLib::isFloatHex("0x.")); + ASSERT_EQUALS(false, MathLib::isFloatHex("0XP")); + ASSERT_EQUALS(false, MathLib::isFloatHex("0xx")); + } + + void isinthex() const { // hex number syntax: [sign]0x[hexnumbers][suffix] // positive testing - ASSERT_EQUALS(true, MathLib::isHex("0xa")); - ASSERT_EQUALS(true, MathLib::isHex("0x2AF3")); - ASSERT_EQUALS(true, MathLib::isHex("-0xa")); - ASSERT_EQUALS(true, MathLib::isHex("-0x2AF3")); - ASSERT_EQUALS(true, MathLib::isHex("+0xa")); - ASSERT_EQUALS(true, MathLib::isHex("+0x2AF3")); - ASSERT_EQUALS(true, MathLib::isHex("0x0")); - ASSERT_EQUALS(true, MathLib::isHex("+0x0")); - ASSERT_EQUALS(true, MathLib::isHex("-0x0")); - ASSERT_EQUALS(true, MathLib::isHex("+0x0U")); - ASSERT_EQUALS(true, MathLib::isHex("-0x0U")); - ASSERT_EQUALS(true, MathLib::isHex("+0x0L")); - ASSERT_EQUALS(true, MathLib::isHex("-0x0L")); - ASSERT_EQUALS(true, MathLib::isHex("+0x0LU")); - ASSERT_EQUALS(true, MathLib::isHex("-0x0LU")); - ASSERT_EQUALS(true, MathLib::isHex("+0x0UL")); - ASSERT_EQUALS(true, MathLib::isHex("-0x0UL")); - ASSERT_EQUALS(true, MathLib::isHex("+0x0LL")); - ASSERT_EQUALS(true, MathLib::isHex("-0x0LL")); - ASSERT_EQUALS(true, MathLib::isHex("+0x0ULL")); - ASSERT_EQUALS(true, MathLib::isHex("-0x0ULL")); - ASSERT_EQUALS(true, MathLib::isHex("+0x0LLU")); - ASSERT_EQUALS(true, MathLib::isHex("-0x0LLU")); + ASSERT_EQUALS(true, MathLib::isIntHex("0xa")); + ASSERT_EQUALS(true, MathLib::isIntHex("0x2AF3")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0xa")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x2AF3")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0xa")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x2AF3")); + ASSERT_EQUALS(true, MathLib::isIntHex("0x0")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0U")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0U")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0L")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0L")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0LU")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0LU")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0UL")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0UL")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0LL")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0LL")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0ULL")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0ULL")); + ASSERT_EQUALS(true, MathLib::isIntHex("+0x0LLU")); + ASSERT_EQUALS(true, MathLib::isIntHex("-0x0LLU")); // negative testing - ASSERT_EQUALS(false, MathLib::isHex("+0x")); - ASSERT_EQUALS(false, MathLib::isHex("-0x")); - ASSERT_EQUALS(false, MathLib::isHex("0x")); - ASSERT_EQUALS(false, MathLib::isHex("0xx")); - ASSERT_EQUALS(false, MathLib::isHex("-0175")); - ASSERT_EQUALS(false, MathLib::isHex("-0_garbage_")); - ASSERT_EQUALS(false, MathLib::isHex(" ")); - ASSERT_EQUALS(false, MathLib::isHex(" ")); - ASSERT_EQUALS(false, MathLib::isHex("0")); - ASSERT_EQUALS(false, MathLib::isHex("+0x0Z")); - ASSERT_EQUALS(false, MathLib::isHex("-0x0Z")); - ASSERT_EQUALS(false, MathLib::isHex("+0x0Uz")); - ASSERT_EQUALS(false, MathLib::isHex("-0x0Uz")); - ASSERT_EQUALS(false, MathLib::isHex("+0x0Lz")); - ASSERT_EQUALS(false, MathLib::isHex("-0x0Lz")); - ASSERT_EQUALS(false, MathLib::isHex("+0x0LUz")); - ASSERT_EQUALS(false, MathLib::isHex("-0x0LUz")); - ASSERT_EQUALS(false, MathLib::isHex("+0x0ULz")); - ASSERT_EQUALS(false, MathLib::isHex("-0x0ULz")); - ASSERT_EQUALS(false, MathLib::isHex("+0x0LLz")); - ASSERT_EQUALS(false, MathLib::isHex("-0x0LLz")); - ASSERT_EQUALS(false, MathLib::isHex("+0x0ULLz")); - ASSERT_EQUALS(false, MathLib::isHex("-0x0ULLz")); - ASSERT_EQUALS(false, MathLib::isHex("+0x0LLUz")); - ASSERT_EQUALS(false, MathLib::isHex("-0x0LLUz")); - ASSERT_EQUALS(false, MathLib::isHex("0x0+0")); - ASSERT_EQUALS(false, MathLib::isHex("e2")); - ASSERT_EQUALS(false, MathLib::isHex("+E2")); + ASSERT_EQUALS(false, MathLib::isIntHex("+0x")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0x")); + ASSERT_EQUALS(false, MathLib::isIntHex("0x")); + ASSERT_EQUALS(false, MathLib::isIntHex("0xx")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0175")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0_garbage_")); + ASSERT_EQUALS(false, MathLib::isIntHex(" ")); + ASSERT_EQUALS(false, MathLib::isIntHex(" ")); + ASSERT_EQUALS(false, MathLib::isIntHex("0")); + ASSERT_EQUALS(false, MathLib::isIntHex("+0x0Z")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0x0Z")); + ASSERT_EQUALS(false, MathLib::isIntHex("+0x0Uz")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0x0Uz")); + ASSERT_EQUALS(false, MathLib::isIntHex("+0x0Lz")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0x0Lz")); + ASSERT_EQUALS(false, MathLib::isIntHex("+0x0LUz")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0x0LUz")); + ASSERT_EQUALS(false, MathLib::isIntHex("+0x0ULz")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0x0ULz")); + ASSERT_EQUALS(false, MathLib::isIntHex("+0x0LLz")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0x0LLz")); + ASSERT_EQUALS(false, MathLib::isIntHex("+0x0ULLz")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0x0ULLz")); + ASSERT_EQUALS(false, MathLib::isIntHex("+0x0LLUz")); + ASSERT_EQUALS(false, MathLib::isIntHex("-0x0LLUz")); + ASSERT_EQUALS(false, MathLib::isIntHex("0x0+0")); + ASSERT_EQUALS(false, MathLib::isIntHex("e2")); + ASSERT_EQUALS(false, MathLib::isIntHex("+E2")); // test empty string - ASSERT_EQUALS(false, MathLib::isHex("")); + ASSERT_EQUALS(false, MathLib::isIntHex("")); } - void isValidSuffix(void) const { + void isValidIntegerSuffix(void) const { // negative testing std::string value = "ux"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "ulx"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "lx"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "lux"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "lll"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "garbage"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = ""; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "llu "; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "i"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "iX"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "i6X"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "i64X"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "i64 "; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "i66"; - ASSERT_EQUALS(false, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(false, MathLib::isValidIntegerSuffix(value.begin(), value.end())); // positive testing value = "u"; - ASSERT_EQUALS(true, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "ul"; - ASSERT_EQUALS(true, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "ull"; - ASSERT_EQUALS(true, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "l"; - ASSERT_EQUALS(true, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "lu"; - ASSERT_EQUALS(true, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "ll"; - ASSERT_EQUALS(true, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "llu"; - ASSERT_EQUALS(true, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix(value.begin(), value.end())); value = "i64"; - ASSERT_EQUALS(true, MathLib::isValidSuffix(value.begin(), value.end())); + ASSERT_EQUALS(true, MathLib::isValidIntegerSuffix(value.begin(), value.end())); } void ispositive() const {