From ed793793db42a9acc4dfe3df646201e4d3bcd3c3 Mon Sep 17 00:00:00 2001 From: orbitcowboy Date: Tue, 11 Mar 2014 20:02:04 +0100 Subject: [PATCH 1/3] MathLib:isHex(): fix detection of missing suffixes (U,L). --- lib/mathlib.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++-- lib/mathlib.h | 7 ++++ test/testmathlib.cpp | 60 +++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 3 deletions(-) diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index a8b047a0a..91505552d 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -210,10 +210,95 @@ bool MathLib::isOct(const std::string& s) || (state == SUFFIX_ULL) || (state == SUFFIX_LLU); } -bool MathLib::isHex(const std::string& str) +bool MathLib::isHex(const std::string& s) { - const bool sign = str[0]=='-' || str[0]=='+'; - return (str.compare(sign?1:0, 2, "0x") == 0 || str.compare(sign?1:0, 2, "0X") == 0); + // return false, in case an empty string is provided + if (s.empty()) + return false; + + enum {START, PLUSMINUS, HEX_PREFIX, DIGIT, DIGITS, SUFFIX_U, SUFFIX_UL, SUFFIX_ULL, SUFFIX_L, SUFFIX_LU, SUFFIX_LL, SUFFIX_LLU} 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 = DIGIT; + else + return false; + break; + case DIGIT: + if (isHexDigit(*it)) + state = DIGITS; + else + return false; + break; + case DIGITS: + if (isHexDigit(*it)) + state = DIGITS; + else if (*it == 'u' || *it == 'U') + state = SUFFIX_U; + else if (*it == 'l' || *it == 'L') + state = SUFFIX_L; + else + return false; + break; + case SUFFIX_U: + if (*it == 'l' || *it == 'L') + state = SUFFIX_UL; // UL + else + return false; + break; + case SUFFIX_UL: + if (*it == 'l' || *it == 'L') + state = SUFFIX_ULL; // ULL + else + return false; + break; + case SUFFIX_L: + if (*it == 'u' || *it == 'U') + state = SUFFIX_LU; // LU + else if (*it == 'l' || *it == 'L') + state = SUFFIX_LL; // LL + else + return false; + break; + case SUFFIX_LU: + return false; + break; + case SUFFIX_LL: + if (*it == 'u' || *it == 'U') + state = SUFFIX_LLU; // LLU + else + return false; + break; + default: + return false; + } + } + return (state == DIGITS) + || (state == SUFFIX_U) || (state == SUFFIX_L) + || (state == SUFFIX_UL) || (state == SUFFIX_LU) || (state == SUFFIX_LL) + || (state == SUFFIX_ULL) || (state == SUFFIX_LLU); +} + +bool MathLib::isHexDigit(char c) +{ + return (c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9' + || c == 'A' || c == 'B' || c == 'C' || c == 'D' || c == 'E' || c == 'F' + || c == 'a' || c == 'b' || c == 'c' || c == 'd' || c == 'e' || c == 'f'); } /*! \brief Does the string represent a binary number? diff --git a/lib/mathlib.h b/lib/mathlib.h index 708cff03b..94729daa0 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -74,6 +74,13 @@ public: * @return true if given character is octal digit. */ static bool isOctalDigit(char c); + + /** + * Return true if given character is 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F. + * @param c The character to check + * @return true if given character is hex digit. + */ + static bool isHexDigit(char c); }; template<> CPPCHECKLIB std::string MathLib::toString(double value); // Declare specialization to avoid linker problems diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 9439c9dd6..531dda775 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -35,6 +35,7 @@ private: TEST_CASE(isint); TEST_CASE(isbin); TEST_CASE(isoct); + TEST_CASE(ishex); TEST_CASE(isnegative); TEST_CASE(ispositive); TEST_CASE(isfloat); @@ -429,6 +430,65 @@ private: ASSERT_EQUALS(false, MathLib::isOct(" -042ULL ")); } + void ishex() { + // 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")); + + // 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")); + + // test empty string + ASSERT_EQUALS(false, MathLib::isHex("")); + } + void ispositive() const { ASSERT_EQUALS(false, MathLib::isPositive("-1")); ASSERT_EQUALS(false, MathLib::isPositive("-1.")); From 71ee625aab4b28e21dd017e5a843002311652638 Mon Sep 17 00:00:00 2001 From: orbitcowboy Date: Fri, 14 Mar 2014 09:33:20 +0100 Subject: [PATCH 2/3] MathLib: replaced isHexDigit function by isxdigit. --- lib/mathlib.cpp | 11 ++--------- lib/mathlib.h | 7 ------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 91505552d..a7b6e11d0 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -240,13 +240,13 @@ bool MathLib::isHex(const std::string& s) return false; break; case DIGIT: - if (isHexDigit(*it)) + if (isxdigit(*it)) state = DIGITS; else return false; break; case DIGITS: - if (isHexDigit(*it)) + if (isxdigit(*it)) state = DIGITS; else if (*it == 'u' || *it == 'U') state = SUFFIX_U; @@ -294,13 +294,6 @@ bool MathLib::isHex(const std::string& s) || (state == SUFFIX_ULL) || (state == SUFFIX_LLU); } -bool MathLib::isHexDigit(char c) -{ - return (c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9' - || c == 'A' || c == 'B' || c == 'C' || c == 'D' || c == 'E' || c == 'F' - || c == 'a' || c == 'b' || c == 'c' || c == 'd' || c == 'e' || c == 'f'); -} - /*! \brief Does the string represent a binary number? * In case leading or trailing white space is provided, the function * returns false. diff --git a/lib/mathlib.h b/lib/mathlib.h index 94729daa0..708cff03b 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -74,13 +74,6 @@ public: * @return true if given character is octal digit. */ static bool isOctalDigit(char c); - - /** - * Return true if given character is 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F. - * @param c The character to check - * @return true if given character is hex digit. - */ - static bool isHexDigit(char c); }; template<> CPPCHECKLIB std::string MathLib::toString(double value); // Declare specialization to avoid linker problems From 74d10cd6d9760a85190099a1bf49b081fa9376c3 Mon Sep 17 00:00:00 2001 From: orbitcowboy Date: Fri, 14 Mar 2014 11:46:41 +0100 Subject: [PATCH 3/3] Added function MathLib::isValidSuffix() --- lib/mathlib.cpp | 108 +++++++++++------------------------------------- lib/mathlib.h | 2 + 2 files changed, 27 insertions(+), 83 deletions(-) diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index a7b6e11d0..24ba56731 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -137,7 +137,7 @@ bool MathLib::isPositive(const std::string &s) **/ bool MathLib::isOct(const std::string& s) { - enum {START, PLUSMINUS, OCTAL_PREFIX, DIGITS, UNSIGNED_SUFFIX, SUFFIX_U, SUFFIX_UL, SUFFIX_ULL, SUFFIX_L, SUFFIX_LU, SUFFIX_LL, SUFFIX_LLU} state = START; + enum {START, PLUSMINUS, OCTAL_PREFIX, DIGITS} state = START; for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { switch (state) { case START: @@ -154,7 +154,6 @@ bool MathLib::isOct(const std::string& s) else return false; break; - case OCTAL_PREFIX: if (isOctalDigit(*it)) state = DIGITS; @@ -164,50 +163,14 @@ bool MathLib::isOct(const std::string& s) case DIGITS: if (isOctalDigit(*it)) state = DIGITS; - else if (*it == 'u' || *it == 'U') - state = SUFFIX_U; - else if (*it == 'l' || *it == 'L') - state = SUFFIX_L; else - return false; - break; - case SUFFIX_U: - if (*it == 'l' || *it == 'L') - state = SUFFIX_UL; // UL - else - return false; - break; - case SUFFIX_UL: - if (*it == 'l' || *it == 'L') - state = SUFFIX_ULL; // ULL - else - return false; - break; - case SUFFIX_L: - if (*it == 'u' || *it == 'U') - state = SUFFIX_LU; // LU - else if (*it == 'l' || *it == 'L') - state = SUFFIX_LL; // LL - else - return false; - break; - case SUFFIX_LU: - return false; - break; - case SUFFIX_LL: - if (*it == 'u' || *it == 'U') - state = SUFFIX_LLU; // LLU - else - return false; + return isValidSuffix(it,s.end()); break; default: return false; } } - return (state == DIGITS) - || (state == SUFFIX_U) || (state == SUFFIX_L) - || (state == SUFFIX_UL) || (state == SUFFIX_LU) || (state == SUFFIX_LL) - || (state == SUFFIX_ULL) || (state == SUFFIX_LLU); + return state == DIGITS; } bool MathLib::isHex(const std::string& s) @@ -216,7 +179,7 @@ bool MathLib::isHex(const std::string& s) if (s.empty()) return false; - enum {START, PLUSMINUS, HEX_PREFIX, DIGIT, DIGITS, SUFFIX_U, SUFFIX_UL, SUFFIX_ULL, SUFFIX_L, SUFFIX_LU, SUFFIX_LL, SUFFIX_LLU} state = START; + enum {START, PLUSMINUS, HEX_PREFIX, DIGIT, DIGITS} state = START; for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { switch (state) { case START: @@ -248,7 +211,23 @@ bool MathLib::isHex(const std::string& s) case DIGITS: if (isxdigit(*it)) state = DIGITS; - else if (*it == 'u' || *it == 'U') + else + return isValidSuffix(it,s.end()); + break; + default: + return false; + } + } + return state == DIGITS; +} + +bool MathLib::isValidSuffix(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} state = START; + for (; it != end; ++it) { + switch (state) { + case START: + if (*it == 'u' || *it == 'U') state = SUFFIX_U; else if (*it == 'l' || *it == 'L') state = SUFFIX_L; @@ -288,8 +267,7 @@ bool MathLib::isHex(const std::string& s) return false; } } - return (state == DIGITS) - || (state == SUFFIX_U) || (state == SUFFIX_L) + return (state == SUFFIX_U) || (state == SUFFIX_L) || (state == SUFFIX_UL) || (state == SUFFIX_LU) || (state == SUFFIX_LL) || (state == SUFFIX_ULL) || (state == SUFFIX_LLU); } @@ -305,7 +283,7 @@ bool MathLib::isHex(const std::string& s) **/ bool MathLib::isBin(const std::string& s) { - enum {START, PLUSMINUS, GNU_BIN_PREFIX, DIGIT, DIGITS, SUFFIX_U, SUFFIX_UL, SUFFIX_ULL, SUFFIX_L, SUFFIX_LU, SUFFIX_LL, SUFFIX_LLU} state = START; + enum {START, PLUSMINUS, GNU_BIN_PREFIX, DIGIT, DIGITS} state = START; for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { switch (state) { case START: @@ -337,50 +315,14 @@ bool MathLib::isBin(const std::string& s) case DIGITS: if (*it == '0' || *it == '1') state = DIGITS; - else if (*it == 'u' || *it == 'U') - state = SUFFIX_U; - else if (*it == 'l' || *it == 'L') - state = SUFFIX_L; else - return false; - break; - case SUFFIX_U: - if (*it == 'l' || *it == 'L') - state = SUFFIX_UL; // UL - else - return false; - break; - case SUFFIX_UL: - if (*it == 'l' || *it == 'L') - state = SUFFIX_ULL; // ULL - else - return false; - break; - case SUFFIX_L: - if (*it == 'u' || *it == 'U') - state = SUFFIX_LU; // LU - else if (*it == 'l' || *it == 'L') - state = SUFFIX_LL; // LL - else - return false; - break; - case SUFFIX_LU: - return false; - break; - case SUFFIX_LL: - if (*it == 'u' || *it == 'U') - state = SUFFIX_LLU; // LLU - else - return false; + return isValidSuffix(it,s.end()); break; default: return false; } } - return (state == DIGITS) - || (state == SUFFIX_U) || (state == SUFFIX_L) - || (state == SUFFIX_UL) || (state == SUFFIX_LU) || (state == SUFFIX_LL) - || (state == SUFFIX_ULL) || (state == SUFFIX_LLU); + return state == DIGITS; } bool MathLib::isInt(const std::string & s) diff --git a/lib/mathlib.h b/lib/mathlib.h index 708cff03b..8dd8df604 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -50,6 +50,8 @@ public: 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 std::string add(const std::string & first, const std::string & second); static std::string subtract(const std::string & first, const std::string & second); static std::string multiply(const std::string & first, const std::string & second);