diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 3e2fc30d4..a6fb9608c 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -138,10 +138,93 @@ bool MathLib::isHex(const std::string& str) return (str.compare(sign?1:0, 2, "0x") == 0 || str.compare(sign?1:0, 2, "0X") == 0); } -bool MathLib::isBin(const std::string& str) +/*! \brief Does the string represent a binary number? + * In case leading or trailing white space is provided, the function + * returns false. + * Additional information can be found here: + * http://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html + * + * \param[in] s The string to check. In case the string is empty, the function returns false. + * \return Return true in case a binary number is provided and false otherwise. + **/ +bool MathLib::isBin(const std::string& s) { - const bool sign = str[0]=='-' || str[0]=='+'; - return ((str.compare(sign?1:0, 2, "0b") == 0 || str.compare(sign?1:0, 2, "0B") == 0) && str.find_first_not_of("10bB", 1) == std::string::npos); + enum {START, PLUSMINUS, GNU_BIN_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 = GNU_BIN_PREFIX; + else + return false; + break; + case PLUSMINUS: + if (*it == '0') + state = GNU_BIN_PREFIX; + else + return false; + break; + case GNU_BIN_PREFIX: + if (*it == 'b' || *it == 'B') + state = DIGIT; + else + return false; + break; + case DIGIT: + if (*it == '0' || *it == '1') + state = DIGITS; + else + return false; + break; + 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; + 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::isInt(const std::string & s) diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index c4afa63d0..0ed5a38c1 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -33,6 +33,7 @@ private: TEST_CASE(calculate1); TEST_CASE(convert); TEST_CASE(isint); + TEST_CASE(isbin); TEST_CASE(isnegative); TEST_CASE(ispositive); TEST_CASE(isfloat); @@ -312,6 +313,46 @@ private: ASSERT_EQUALS(false, MathLib::isInt("LL")); } + void isbin() { + // positive testing + ASSERT_EQUALS(true, MathLib::isBin("0b0")); + ASSERT_EQUALS(true, MathLib::isBin("0b1")); + ASSERT_EQUALS(true, MathLib::isBin("+0b1")); + ASSERT_EQUALS(true, MathLib::isBin("-0b1")); + ASSERT_EQUALS(true, MathLib::isBin("0b11010111")); + ASSERT_EQUALS(true, MathLib::isBin("-0b11010111")); + ASSERT_EQUALS(true, MathLib::isBin("0B11010111")); + ASSERT_EQUALS(true, MathLib::isBin("0b11010111u")); + ASSERT_EQUALS(true, MathLib::isBin("0b11010111ul")); + ASSERT_EQUALS(true, MathLib::isBin("0b11010111ull")); + ASSERT_EQUALS(true, MathLib::isBin("0b11010111l")); + ASSERT_EQUALS(true, MathLib::isBin("0b11010111ll")); + ASSERT_EQUALS(true, MathLib::isBin("0b11010111llu")); + ASSERT_EQUALS(true, MathLib::isBin("0b11010111l")); + ASSERT_EQUALS(true, MathLib::isBin("0b11010111lu")); + ASSERT_EQUALS(false, MathLib::isBin("0b11010111lul")); // Suffix LUL not allowed + + // negative testing + ASSERT_EQUALS(false, MathLib::isBin("100101bx")); + ASSERT_EQUALS(false, MathLib::isBin("0")); + ASSERT_EQUALS(false, MathLib::isBin("0B")); + ASSERT_EQUALS(false, MathLib::isBin("0C")); + ASSERT_EQUALS(false, MathLib::isBin("+0B")); + ASSERT_EQUALS(false, MathLib::isBin("-0B")); + ASSERT_EQUALS(false, MathLib::isBin("-0Bx")); + ASSERT_EQUALS(false, MathLib::isBin("0b11010111x")); + ASSERT_EQUALS(false, MathLib::isBin("0b11010111ux")); + ASSERT_EQUALS(false, MathLib::isBin("0b11010111lx")); + ASSERT_EQUALS(false, MathLib::isBin("0b11010111lux")); + ASSERT_EQUALS(false, MathLib::isBin("0b11010111ulx")); + ASSERT_EQUALS(false, MathLib::isBin("0b11010111lulx")); + ASSERT_EQUALS(false, MathLib::isBin("0b11010111ullx")); + ASSERT_EQUALS(false, MathLib::isBin("0b11010111lll")); + + // test empty string + ASSERT_EQUALS(false, MathLib::isBin("")); + } + void isnegative() const { ASSERT_EQUALS(true , MathLib::isNegative("-1")); ASSERT_EQUALS(true , MathLib::isNegative("-1."));