Skip to content

Commit

Permalink
Remove support for float literals starting with a period
Browse files Browse the repository at this point in the history
Before this patch, writing .0 instead of 0.0 was allowed, as in C, C++, D,
Java, Go, Perl, Python and many other languages. This required a hack in the
form of an additional entry pointer for our scanner. We now get rid of it,
matching languages like Ada, Haskell, OCaml, Rust, Swift.
  • Loading branch information
fingolfin committed May 6, 2020
1 parent 5011e6b commit 9f9c8b6
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 78 deletions.
13 changes: 4 additions & 9 deletions src/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -1431,8 +1431,10 @@ static void ReadFuncExprAbbrevSingle(ReaderState * rs, TypSymbolSet follow)
** all symbols up to one contained in <follow>.
**
** <Literal> := <Int>
** | <Float>
** | 'true'
** | 'false'
** | '~'
** | <Char>
** | <Perm>
** | <String>
Expand All @@ -1448,13 +1450,6 @@ static void ReadFuncExprAbbrevSingle(ReaderState * rs, TypSymbolSet follow)
*/
static void ReadLiteral(ReaderState * rs, TypSymbolSet follow, Char mode)
{
if (rs->s.Symbol == S_DOT) {
// HACK: The only way a dot could turn up here is in a floating point
// literal that starts with '.'. Call back to the scanner to deal
// with this.
ScanForFloatAfterDotHACK(&rs->s);
}

switch (rs->s.Symbol) {

/* <Int> */
Expand Down Expand Up @@ -1497,7 +1492,7 @@ static void ReadLiteral(ReaderState * rs, TypSymbolSet follow, Char mode)
Match_(rs, S_CHAR, "character", follow);
break;

/* string */
/* <String> */
case S_STRING:
GAP_ASSERT(rs->s.ValueObj != 0);
TRY_IF_NO_ERROR { IntrStringExpr(&rs->intr, rs->s.ValueObj); }
Expand All @@ -1510,7 +1505,7 @@ static void ReadLiteral(ReaderState * rs, TypSymbolSet follow, Char mode)
ReadListExpr(rs, follow);
break;

/* <Rec> */
/* <Record> */
case S_REC:
ReadRecExpr(rs, follow);
break;
Expand Down
43 changes: 6 additions & 37 deletions src/scanner.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,10 +361,6 @@ static UInt GetIdent(ScannerState * s, Int i, Char c)
**
** When 's->Value' is completely filled, then a GAP string object is
** created in 's->ValueObj' and all data is stored there.
**
** The argument is used to signal if a decimal point was already read,
** or whether we are starting from scratch..
**
*/
static UInt AddCharToBuf(Obj * string, Char * buf, UInt bufsize, UInt pos, Char c)
{
Expand All @@ -381,24 +377,20 @@ static UInt AddCharToValue(ScannerState * s, UInt pos, Char c)
return AddCharToBuf(&s->ValueObj, s->Value, MAX_VALUE_LEN - 1, pos, c);
}

static UInt GetNumber(ScannerState * s, Int readDecimalPoint, Char c)
static UInt GetNumber(ScannerState * s, Char c)
{
UInt symbol = S_ILLEGAL;
UInt i = 0;
UInt seenADigit = 0;
UInt seenExp = 0;
UInt seenExpDigit = 0;

s->ValueObj = 0;

if (readDecimalPoint) {
s->Value[i++] = '.';
}
else {
GAP_ASSERT(IsDigit(c));

// read initial sequence of digits into 'Value'
while (IsDigit(c)) {
i = AddCharToValue(s, i, c);
seenADigit = 1;
c = GET_NEXT_CHAR();
}

Expand Down Expand Up @@ -448,21 +440,15 @@ static UInt GetNumber(ScannerState * s, Int readDecimalPoint, Char c)
symbol = S_INT;
goto finish;
}
}


// When we get here we have read possibly some digits, a . and possibly
// some more digits, but not an e,E,d,D,q or Q
// When we get here we have read some digits and a dot

// read digits
// read digits after dot
while (IsDigit(c)) {
i = AddCharToValue(s, i, c);
seenADigit = 1;
c = GET_NEXT_CHAR();
}
if (!seenADigit)
SyntaxError(s, "Badly formed number: need a digit before or after the "
"decimal point");
if (c == '\\')
SyntaxError(s, "Badly formed number");

Expand Down Expand Up @@ -502,9 +488,6 @@ static UInt GetNumber(ScannerState * s, Int readDecimalPoint, Char c)
// If the next thing is the start of the exponential notation, read it now.

if (IsAlpha(c)) {
if (!seenADigit)
SyntaxError(s, "Badly formed number: need a digit before or after "
"the decimal point");
seenExp = 1;
i = AddCharToValue(s, i, c);
c = GET_NEXT_CHAR();
Expand All @@ -517,9 +500,6 @@ static UInt GetNumber(ScannerState * s, Int readDecimalPoint, Char c)
// Either we saw an exponent indicator, or we hit end of token deal with
// the end of token case
if (!seenExp) {
if (!seenADigit)
SyntaxError(s, "Badly formed number: need a digit before or after "
"the decimal point");
// Might be a conversion marker
if (IsAlpha(c) && c != 'e' && c != 'E' && c != 'd' && c != 'D' &&
c != 'q' && c != 'Q') {
Expand Down Expand Up @@ -593,17 +573,6 @@ static UInt GetNumber(ScannerState * s, Int readDecimalPoint, Char c)
}


/****************************************************************************
**
*F ScanForFloatAfterDotHACK()
**
*/
void ScanForFloatAfterDotHACK(ScannerState * s)
{
s->Symbol = GetNumber(s, 1, PEEK_CURR_CHAR());
}


/****************************************************************************
**
*F GetOctalDigits()
Expand Down Expand Up @@ -1032,7 +1001,7 @@ static UInt NextSymbol(ScannerState * s)

case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return GetNumber(s, 0, c);
return GetNumber(s, c);

case '\377': symbol = S_EOF; FlushRestOfInputLine(); break;

Expand Down
13 changes: 0 additions & 13 deletions src/scanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,17 +361,4 @@ void Match(ScannerState * s,
TypSymbolSet skipto);


/****************************************************************************
**
*F ScanForFloatAfterDotHACK()
**
** This function is called by 'ReadLiteral' if it encounters a single dot in
** form the of the symbol 'S_DOT'. The only legal way this could happen is
** if the dot is the start of a float literal like '.123'. As the scanner
** cannot detect this without being context aware, we must provide this
** function to allow the reader to signal to the scanner about this.
*/
void ScanForFloatAfterDotHACK(ScannerState * s);


#endif // GAP_SCANNER_H
5 changes: 2 additions & 3 deletions tst/testbugfix/2013-08-21-t00295.tst
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# 2013/08/21 (MH)
gap> . . . .
Syntax error: Badly formed number: need a digit before or after the decimal po\
int in stream:1
Syntax error: literal expected in stream:1
. . . .
^
Syntax error: Record component name expected in stream:2
Syntax error: ; expected in stream:2
2 changes: 1 addition & 1 deletion tst/testinstall/float.tst
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,7 @@ gap> ComplexConjugate(1.3);
#
gap> Display(1.3);
1.3
gap> Display(-.4e6);
gap> Display(-0.4e6);
-400000.
gap> PrintObj(1.3); Print("Q\n");
1.3Q
Expand Down
25 changes: 10 additions & 15 deletions tst/testinstall/longnumber.tst
Original file line number Diff line number Diff line change
Expand Up @@ -152,40 +152,35 @@ gap> 1.;
1.
gap> 0.;
0.
gap> .1;
0.1
gap> 0.1;
0.1
gap> 1111111111111111111111111111111111111.1;
1.11111e+36
gap> 1.11111111111111111111111111111111111111;
1.11111
gap> .;
Syntax error: Badly formed number: need a digit before or after the decimal po\
int in stream:1
Syntax error: literal expected in stream:1
.;
^
gap> .n;
Syntax error: Badly formed number: need a digit before or after the decimal po\
int in stream:1
Syntax error: literal expected in stream:1
.n;
^
gap> .q;
Syntax error: Badly formed number: need a digit before or after the decimal po\
int in stream:1
Syntax error: literal expected in stream:1
.q;
^
gap> .0n;
Error, failed to convert float literal
Syntax error: literal expected in stream:1
.0n;
^
gap> .0q;
Syntax error: Badly formed number: need at least one digit in the exponent in \
stream:1
Syntax error: literal expected in stream:1
.0q;
^^^
^
gap> .0qn;
Syntax error: Badly formed number: need at least one digit in the exponent in \
stream:1
Syntax error: literal expected in stream:1
.0qn;
^^^
^
gap> Unbind(x);
gap> STOP_TEST( "longnumber.tst", 1);

0 comments on commit 9f9c8b6

Please sign in to comment.