(perl #131725) ignore the exponent on a decimal float if no digits
authorTony Cook <tony@develop-help.com>
Thu, 3 Aug 2017 02:11:56 +0000 (12:11 +1000)
committerTony Cook <tony@develop-help.com>
Mon, 14 Aug 2017 05:38:54 +0000 (15:38 +1000)
Previously the "1e-" in "1e--5" would be treated as "1", but consumed
the "e-".

This wasn't an issue for hex floats.

I considered (and implemented) croaking instead, but this was
inconsistent with the behaviour for hex floats, which only reach this
code if a full hex float has been parsed.

t/lib/croak/toke
toke.c

index 2603224..c477be0 100644 (file)
@@ -394,3 +394,13 @@ $a = <<~ ;
 
 EXPECT
 Use of bare << to mean <<"" is forbidden at - line 1.
+########
+# NAME incomplete floating point decimal exponent (#131725)
+1e--5
+EXPECT
+Bareword found where operator expected at - line 1, near "1e"
+       (Missing operator before e?)
+Number found where operator expected at - line 1, near "--5"
+       (Missing operator before 5?)
+syntax error at - line 1, near "1e"
+Execution of - aborted due to compilation errors.
diff --git a/toke.c b/toke.c
index 6aa5f26..6de7d09 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -11182,9 +11182,11 @@ Perl_scan_num(pTHX_ const char *start, YYSTYPE* lvalp)
               || UNLIKELY(hexfp && isALPHA_FOLD_EQ(*s, 'p')))
             && strchr("+-0123456789_", s[1]))
         {
-            floatit = TRUE;
+            int exp_digits = 0;
+            const char *save_s = s;
+            char * save_d = d;
 
-           /* regardless of whether user said 3E5 or 3e5, use lower 'e',
+            /* regardless of whether user said 3E5 or 3e5, use lower 'e',
                ditto for p (hexfloats) */
             if ((isALPHA_FOLD_EQ(*s, 'e'))) {
                /* At least some Mach atof()s don't grok 'E' */
@@ -11216,6 +11218,7 @@ Perl_scan_num(pTHX_ const char *start, YYSTYPE* lvalp)
            /* read digits of exponent */
            while (isDIGIT(*s) || *s == '_') {
                if (isDIGIT(*s)) {
+                    ++exp_digits;
                    if (d >= e)
                        Perl_croak(aTHX_ "%s", number_too_long);
                    *d++ = *s++;
@@ -11227,6 +11230,20 @@ Perl_scan_num(pTHX_ const char *start, YYSTYPE* lvalp)
                   lastub = s++;
                }
            }
+
+            if (!exp_digits) {
+                /* no exponent digits, the [eEpP] could be for something else,
+                 * though in practice we don't get here for p since that's preparsed
+                 * earlier, and results in only the 0xX being consumed, so behave similarly
+                 * for decimal floats and consume only the D.DD, leaving the [eE] to the
+                 * next token.
+                 */
+                s = save_s;
+                d = save_d;
+            }
+            else {
+                floatit = TRUE;
+            }
        }