From 66a96c82746118c70a447d7768b0428e15d2f5ad Mon Sep 17 00:00:00 2001 From: Eike Rathke Date: Tue, 15 Oct 2013 12:17:46 +0200 Subject: clean up SbiScanner::NextSym() a little, fdo#70319 follow-up Number recognition was suboptimal and didn't properly resync scan positions after having detected an error. Change-Id: I278fdaaf17ed40560785deaaad0e3412a249d90a --- basic/qa/cppunit/test_scanner.cxx | 29 ++++++------ basic/source/comp/scanner.cxx | 96 +++++++++++++++++++++++---------------- 2 files changed, 74 insertions(+), 51 deletions(-) diff --git a/basic/qa/cppunit/test_scanner.cxx b/basic/qa/cppunit/test_scanner.cxx index acf740fb03a1..b19e52eeffa8 100644 --- a/basic/qa/cppunit/test_scanner.cxx +++ b/basic/qa/cppunit/test_scanner.cxx @@ -576,10 +576,12 @@ namespace CPPUNIT_ASSERT(errors == 0); symbols = getSymbols(source2, errors); - CPPUNIT_ASSERT(symbols.size() == 2); - CPPUNIT_ASSERT(symbols[0].number == 1.23); + CPPUNIT_ASSERT(symbols.size() == 3); + CPPUNIT_ASSERT(symbols[0].number == 1.2); CPPUNIT_ASSERT(symbols[0].type == SbxDOUBLE); - CPPUNIT_ASSERT(symbols[1].text == cr); + CPPUNIT_ASSERT(rtl::math::round( symbols[1].number, 12) == rtl::math::round( .3, 12)); + CPPUNIT_ASSERT(symbols[1].type == SbxDOUBLE); + CPPUNIT_ASSERT(symbols[2].text == cr); CPPUNIT_ASSERT(errors == 1); symbols = getSymbols(source3, errors); @@ -627,10 +629,11 @@ namespace CPPUNIT_ASSERT(errors == 0); symbols = getSymbols(source9, errors); - CPPUNIT_ASSERT(symbols.size() == 2); - CPPUNIT_ASSERT(symbols[0].number == 12000); + CPPUNIT_ASSERT(symbols.size() == 3); + CPPUNIT_ASSERT(symbols[0].number == 12); CPPUNIT_ASSERT(symbols[0].type == SbxDOUBLE); - CPPUNIT_ASSERT(symbols[1].text == cr); + CPPUNIT_ASSERT(symbols[1].text == OUString("dE3")); + CPPUNIT_ASSERT(symbols[2].text == cr); CPPUNIT_ASSERT(errors == 1); symbols = getSymbols(source10, errors); @@ -647,16 +650,16 @@ namespace CPPUNIT_ASSERT(symbols[1].text == cr); CPPUNIT_ASSERT(errors == 0); - /* FIXME: SbiScanner::NextSym() is total crap, the result of scanning - * "12e++3" should be something different than this.. */ symbols = getSymbols(source12, errors); - CPPUNIT_ASSERT(symbols.size() == 4); + CPPUNIT_ASSERT(symbols.size() == 6); CPPUNIT_ASSERT(symbols[0].number == 12); CPPUNIT_ASSERT(symbols[0].type == SbxDOUBLE); - CPPUNIT_ASSERT(symbols[1].text == OUString("+")); - CPPUNIT_ASSERT(symbols[2].number == 3); - CPPUNIT_ASSERT(symbols[2].type == SbxINTEGER); - CPPUNIT_ASSERT(symbols[3].text == cr); + CPPUNIT_ASSERT(symbols[1].text == OUString("e")); + CPPUNIT_ASSERT(symbols[2].text == OUString("+")); + CPPUNIT_ASSERT(symbols[3].text == OUString("+")); + CPPUNIT_ASSERT(symbols[4].number == 3); + CPPUNIT_ASSERT(symbols[4].type == SbxINTEGER); + CPPUNIT_ASSERT(symbols[5].text == cr); CPPUNIT_ASSERT(errors == 1); symbols = getSymbols(source13, errors); diff --git a/basic/source/comp/scanner.cxx b/basic/source/comp/scanner.cxx index d966406b4f42..0a5a4932f99f 100644 --- a/basic/source/comp/scanner.cxx +++ b/basic/source/comp/scanner.cxx @@ -302,12 +302,12 @@ bool SbiScanner::NextSym() (nCol + 1 < aLine.getLength() && aLine[nCol] == '.' && theBasicCharClass::get().isDigit(aLine[nCol + 1] & 0xFF))) { short exp = 0; - short comma = 0; - short ndig = 0; - short ncdig = 0; + short dec = 0; eScanType = SbxDOUBLE; + bool bScanError = false; bool bBufOverflow = false; - while(nCol < aLine.getLength() && strchr("0123456789.DEde", aLine[nCol])) + // All this because of 'D' or 'd' floating point type, sigh.. + while(!bScanError && nCol < aLine.getLength() && strchr("0123456789.DEde", aLine[nCol])) { // from 4.1.1996: buffer full? -> go on scanning empty if( (p-buf) == (BUF_SIZE-1) ) @@ -319,64 +319,84 @@ bool SbiScanner::NextSym() // point or exponent? if(aLine[nCol] == '.') { - if( ++comma > 1 ) - { - ++pLine; ++nCol; continue; - } + if( ++dec > 1 ) + bScanError = true; else - { - *p = '.'; - ++p, ++pLine, ++nCol; - } + *p++ = '.'; } else if(strchr("DdEe", aLine[nCol])) { if (++exp > 1) + bScanError = true; + else { - ++pLine; ++nCol; continue; - } - - *p = 'E'; - ++p, ++pLine, ++nCol; - - if(aLine[nCol] == '+') - ++pLine, ++nCol; - else if(aLine[nCol] == '-') - { - *p = '-'; - ++p, ++pLine, ++nCol; + *p++ = 'E'; + if (nCol + 1 < aLine.getLength() && (aLine[nCol+1] == '+' || aLine[nCol+1] == '-')) + { + ++pLine, ++nCol; + if( (p-buf) == (BUF_SIZE-1) ) + { + bBufOverflow = true; + continue; + } + *p++ = aLine[nCol]; + } } } else { - *p = aLine[nCol]; - ++p, ++pLine, ++nCol; - if( comma && !exp ) ++ncdig; + *p++ = aLine[nCol]; } - if (!exp) ++ndig; + ++pLine, ++nCol; } *p = 0; aSym = p; bNumber = true; - if( comma > 1 || exp > 1 ) - { aError = OUString('.'); - GenError( SbERR_BAD_CHAR_IN_NUMBER ); } + // For bad characters, scan and parse errors generate only one error. + SbError nError = 0; + if (bScanError) + { + --pLine, --nCol; + aError = OUString( aLine[nCol]); + nError = SbERR_BAD_CHAR_IN_NUMBER; + } rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; const sal_Unicode* pParseEnd = buf; nVal = rtl_math_uStringToDouble( buf, buf+(p-buf), '.', ',', &eStatus, &pParseEnd ); - if (eStatus != rtl_math_ConversionStatus_Ok || pParseEnd != buf+(p-buf)) - GenError( SbERR_MATH_OVERFLOW ); + if (pParseEnd != buf+(p-buf)) + { + // e.g. "12e" or "12e+", or with bScanError "12d"+"E". + sal_Int32 nChars = buf+(p-buf) - pParseEnd; + pLine -= nChars; + nCol -= nChars; + // For bScanError, pLine and nCol were already decremented, just + // add that character to the parse end. + if (bScanError) + ++nChars; + // Copy error position from original string, not the buffer + // replacement where "12dE" => "12EE". + aError = aLine.copy( nCol, nChars); + nError = SbERR_BAD_CHAR_IN_NUMBER; + } + else if (eStatus != rtl_math_ConversionStatus_Ok) + { + // Keep the scan error and character at position, if any. + if (!nError) + nError = SbERR_MATH_OVERFLOW; + } + + if (nError) + GenError( nError ); - ndig = ndig - comma; - if( !comma && !exp ) + if( !dec && !exp ) { if( nVal >= SbxMININT && nVal <= SbxMAXINT ) eScanType = SbxINTEGER; - else - if( nVal >= SbxMINLNG && nVal <= SbxMAXLNG ) - eScanType = SbxLONG; + else if( nVal >= SbxMINLNG && nVal <= SbxMAXLNG ) + eScanType = SbxLONG; } + if( bBufOverflow ) GenError( SbERR_MATH_OVERFLOW ); -- cgit v1.2.3