/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "HexStringParser.h" #include #include #include #include #include #include #include #include #include using namespace decaf; using namespace decaf::util; using namespace decaf::lang; using namespace decaf::lang::exceptions; using namespace decaf::internal; using namespace decaf::internal::util; //////////////////////////////////////////////////////////////////////////////// const std::string HexStringParser::HEX_SIGNIFICANT = "0[xX](\\p{XDigit}+\\.?|\\p{XDigit}*\\.\\p{XDigit}+)"; const std::string HexStringParser::BINARY_EXPONENT = "[pP]([+-]?\\d+)"; const std::string HexStringParser::FLOAT_TYPE_SUFFIX = "[fFdD]?"; const std::string HexStringParser::HEX_PATTERN = "[\\x00-\\x20]*([+-]?)" + HEX_SIGNIFICANT + BINARY_EXPONENT + FLOAT_TYPE_SUFFIX + "[\\x00-\\x20]*"; //////////////////////////////////////////////////////////////////////////////// HexStringParser::HexStringParser(int exponentWidth, int mantissaWidth) : EXPONENT_WIDTH(exponentWidth), MANTISSA_WIDTH(mantissaWidth), EXPONENT_BASE(0), MAX_EXPONENT(0), MIN_EXPONENT(), MANTISSA_MASK(), sign(0), exponent(0), mantissa(0), abandonedNumber() { this->EXPONENT_BASE = ~(-1 << (exponentWidth - 1)); this->MAX_EXPONENT = ~(-1 << exponentWidth); this->MIN_EXPONENT = -(MANTISSA_WIDTH + 1); this->MANTISSA_MASK = ~(-1 << mantissaWidth); } //////////////////////////////////////////////////////////////////////////////// double HexStringParser::parseDouble(const std::string& hexString) { HexStringParser parser(DOUBLE_EXPONENT_WIDTH, DOUBLE_MANTISSA_WIDTH); long long result = parser.parse(hexString); return Double::longBitsToDouble(result); } //////////////////////////////////////////////////////////////////////////////// float HexStringParser::parseFloat(const std::string& hexString) { HexStringParser parser(FLOAT_EXPONENT_WIDTH, FLOAT_MANTISSA_WIDTH); int result = (int) parser.parse(hexString); return Float::intBitsToFloat(result); } //////////////////////////////////////////////////////////////////////////////// long long HexStringParser::parse(const std::string& hexString) { std::string* hexSegments = getSegmentsFromHexString(hexString); std::string signStr = hexSegments[0]; std::string significantStr = hexSegments[1]; std::string exponentStr = hexSegments[2]; delete hexSegments; parseHexSign(signStr); parseExponent(exponentStr); parseMantissa(significantStr); sign <<= (MANTISSA_WIDTH + EXPONENT_WIDTH); exponent <<= MANTISSA_WIDTH; return sign | exponent | mantissa; } //////////////////////////////////////////////////////////////////////////////// std::string* HexStringParser::getSegmentsFromHexString(DECAF_UNUSED const std::string& hexString) { // apr_pool_t* thePool = NULL; // apr_pool_create( &thePool, NULL ); // apr_strmatch_pattern* pattern = // apr_strmatch_precompile( thePool, HEX_PATTERN.c_str(), 0 ); // // std::vector hexSegments; // // TODO // Matcher matcher = PATTERN.matcher(hexString); // if( !matcher.matches() ) { // throw NumberFormatException( // __FILE__, __LINE__, // "HexStringParser::getSegmentsFromHexString" // "Invalid hex string:", hexString.c_str() ); // } // // std::string* hexSegments = new std::string[3]; // hexSegments[0] = matcher.group(1); // hexSegments[1] = matcher.group(2); // hexSegments[2] = matcher.group(3); // // return hexSegments; return NULL; } //////////////////////////////////////////////////////////////////////////////// void HexStringParser::parseExponent(const std::string& exponentStr) { std::string newExponentStr = exponentStr; char leadingChar = newExponentStr.at(0); int expSign = (leadingChar == '-' ? -1 : 1); if (!Character::isDigit(leadingChar)) { newExponentStr = newExponentStr.substr(1, newExponentStr.size()); } try { exponent = expSign * Long::parseLong(exponentStr); checkedAddExponent(EXPONENT_BASE); } catch (exceptions::NumberFormatException& e) { exponent = expSign * Long::MAX_VALUE; } } //////////////////////////////////////////////////////////////////////////////// void HexStringParser::parseMantissa(const std::string& significantStr) { StringTokenizer tokenizer(significantStr, "\\."); std::vector strings; tokenizer.toArray(strings); std::string strIntegerPart = strings[0]; std::string strDecimalPart = strings.size() > 1 ? strings[1] : ""; std::string significand = getNormalizedSignificand(strIntegerPart, strDecimalPart); if (significand == "0") { setZero(); return; } int offset = getOffset(strIntegerPart, strDecimalPart); checkedAddExponent(offset); if (exponent >= MAX_EXPONENT) { setInfinite(); return; } if (exponent <= MIN_EXPONENT) { setZero(); return; } if (significand.length() > MAX_SIGNIFICANT_LENGTH) { abandonedNumber = significand.substr(MAX_SIGNIFICANT_LENGTH); significand = significand.substr(0, MAX_SIGNIFICANT_LENGTH); } mantissa = Long::parseLong(significand, HEX_RADIX); if (exponent >= 1) { processNormalNumber(); } else { processSubNormalNumber(); } } //////////////////////////////////////////////////////////////////////////////// void HexStringParser::checkedAddExponent(long long offset) { long long result = exponent + offset; int expSign = Long::signum(exponent); if (expSign * Long::signum(offset) > 0 && expSign * Long::signum(result) < 0) { exponent = expSign * Long::MAX_VALUE; } else { exponent = result; } } //////////////////////////////////////////////////////////////////////////////// void HexStringParser::processNormalNumber() { int desiredWidth = MANTISSA_WIDTH + 2; fitMantissaInDesiredWidth(desiredWidth); round(); mantissa = mantissa & MANTISSA_MASK; } //////////////////////////////////////////////////////////////////////////////// void HexStringParser::processSubNormalNumber() { int desiredWidth = MANTISSA_WIDTH + 1; desiredWidth += (int) exponent; //lends bit from mantissa to exponent exponent = 0; fitMantissaInDesiredWidth(desiredWidth); round(); mantissa = mantissa & MANTISSA_MASK; } //////////////////////////////////////////////////////////////////////////////// void HexStringParser::fitMantissaInDesiredWidth(int desiredWidth) { int bitLength = countBitsLength(mantissa); if (bitLength > desiredWidth) { discardTrailingBits(bitLength - desiredWidth); } else { mantissa <<= (desiredWidth - bitLength); } } //////////////////////////////////////////////////////////////////////////////// void HexStringParser::discardTrailingBits(long long num) { long long mask = ~(-1L << num); abandonedNumber += (char) (mantissa & mask); mantissa >>= num; } //////////////////////////////////////////////////////////////////////////////// void HexStringParser::round() { std::string result = abandonedNumber; replaceAll(result, "0+", ""); bool moreThanZero = (result.length() > 0 ? true : false); int lastDiscardedBit = (int) (mantissa & 1L); mantissa >>= 1; int tailBitInMantissa = (int) (mantissa & 1L); if (lastDiscardedBit == 1 && (moreThanZero || tailBitInMantissa == 1)) { int oldLength = countBitsLength(mantissa); mantissa += 1L; int newLength = countBitsLength(mantissa); //Rounds up to exponent when whole bits of mantissa are one-bits. if (oldLength >= MANTISSA_WIDTH && newLength > oldLength) { checkedAddExponent(1); } } } //////////////////////////////////////////////////////////////////////////////// std::string HexStringParser::getNormalizedSignificand(const std::string& strIntegerPart, const std::string& strDecimalPart) { std::string significand = strIntegerPart + strDecimalPart; replaceFirst(significand, "^0x", ""); if (significand.length() == 0) { significand = "0"; } return significand; } //////////////////////////////////////////////////////////////////////////////// int HexStringParser::getOffset(const std::string& strIntegerPart, const std::string& strDecimalPart) { std::string strIntegerPart2 = strIntegerPart; replaceFirst(strIntegerPart2, "^0+", ""); //If the Integer part is a nonzero number. if (strIntegerPart.length() != 0) { std::string leadingNumber = strIntegerPart.substr(0, 1); return (int) ((strIntegerPart.length() - 1) * 4 + countBitsLength(Long::parseLong(leadingNumber, HEX_RADIX)) - 1); } //If the Integer part is a zero number. int i; for (i = 0; (std::size_t) i < strDecimalPart.length() && strDecimalPart.at(i) == '0'; i++) { }; if ((std::size_t) i == strDecimalPart.length()) { return 0; } std::string leadingNumber = strDecimalPart.substr(i, i + 1); return (-i - 1) * 4 + countBitsLength(Long::parseLong(leadingNumber, HEX_RADIX)) - 1; } //////////////////////////////////////////////////////////////////////////////// int HexStringParser::countBitsLength(long long value) { int leadingZeros = Long::numberOfLeadingZeros(value); return Long::SIZE - leadingZeros; }