aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ChangeLog25
-rw-r--r--src/data.c42
-rw-r--r--src/lisp.h2
-rw-r--r--src/lread.c149
4 files changed, 106 insertions, 112 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 4a675cc96c6..c232c242fd7 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,28 @@
12011-04-20 Paul Eggert <eggert@cs.ucla.edu>
2
3 Make the Lisp reader and string-to-float more consistent.
4 * data.c (atof): Remove decl; no longer used or needed.
5 (Fstring_to_number): Use new string_to_float function, to be
6 consistent with how the Lisp reader treats infinities and NaNs.
7 Do not assume that floating-point numbers represent EMACS_INT
8 without losing information; this is not true on most 64-bit hosts.
9 Avoid double-rounding errors, by insisting on integers when
10 parsing non-base-10 numbers, as the documentation specifies.
11 Report integer overflow instead of silently converting to
12 integers.
13 * lisp.h (string_to_float): New decl, replacing ...
14 (isfloat_string): Remove.
15 * lread.c (read1): Do not accept +. and -. as integers; this
16 appears to have been a coding error. Similarly, do not accept
17 strings like +-1e0 as floating point numbers. Do not report
18 overflow for some integer overflows and not others; instead,
19 report them all. Break out the floating-point parsing into a new
20 function string_to_float, so that Fstring_to_number parses
21 floating point numbers consistently with the Lisp reader.
22 (string_to_float): New function, replacing isfloat_string.
23 This function checks for valid syntax and produces the resulting
24 Lisp float number too.
25
12011-04-19 Eli Zaretskii <eliz@gnu.org> 262011-04-19 Eli Zaretskii <eliz@gnu.org>
2 27
3 * syntax.h (SETUP_SYNTAX_TABLE_FOR_OBJECT): Fix setting of 28 * syntax.h (SETUP_SYNTAX_TABLE_FOR_OBJECT): Fix setting of
diff --git a/src/data.c b/src/data.c
index c9250a67bf0..c3ee3e39939 100644
--- a/src/data.c
+++ b/src/data.c
@@ -48,10 +48,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
48 48
49#include <math.h> 49#include <math.h>
50 50
51#if !defined (atof)
52extern double atof (const char *);
53#endif /* !atof */
54
55Lisp_Object Qnil, Qt, Qquote, Qlambda, Qunbound; 51Lisp_Object Qnil, Qt, Qquote, Qlambda, Qunbound;
56static Lisp_Object Qsubr; 52static Lisp_Object Qsubr;
57Lisp_Object Qerror_conditions, Qerror_message, Qtop_level; 53Lisp_Object Qerror_conditions, Qerror_message, Qtop_level;
@@ -2415,8 +2411,7 @@ If the base used is not 10, STRING is always parsed as integer. */)
2415{ 2411{
2416 register char *p; 2412 register char *p;
2417 register int b; 2413 register int b;
2418 int sign = 1; 2414 EMACS_INT n;
2419 Lisp_Object val;
2420 2415
2421 CHECK_STRING (string); 2416 CHECK_STRING (string);
2422 2417
@@ -2430,38 +2425,23 @@ If the base used is not 10, STRING is always parsed as integer. */)
2430 xsignal1 (Qargs_out_of_range, base); 2425 xsignal1 (Qargs_out_of_range, base);
2431 } 2426 }
2432 2427
2433 /* Skip any whitespace at the front of the number. Some versions of 2428 /* Skip any whitespace at the front of the number. Typically strtol does
2434 atoi do this anyway, so we might as well make Emacs lisp consistent. */ 2429 this anyway, so we might as well be consistent. */
2435 p = SSDATA (string); 2430 p = SSDATA (string);
2436 while (*p == ' ' || *p == '\t') 2431 while (*p == ' ' || *p == '\t')
2437 p++; 2432 p++;
2438 2433
2439 if (*p == '-') 2434 if (b == 10)
2440 {
2441 sign = -1;
2442 p++;
2443 }
2444 else if (*p == '+')
2445 p++;
2446
2447 if (isfloat_string (p, 1) && b == 10)
2448 val = make_float (sign * atof (p));
2449 else
2450 { 2435 {
2451 double v = 0; 2436 Lisp_Object val = string_to_float (p, 1);
2452 2437 if (FLOATP (val))
2453 while (1) 2438 return val;
2454 {
2455 int digit = digit_to_number (*p++, b);
2456 if (digit < 0)
2457 break;
2458 v = v * b + digit;
2459 }
2460
2461 val = make_fixnum_or_float (sign * v);
2462 } 2439 }
2463 2440
2464 return val; 2441 n = strtol (p, NULL, b);
2442 if (FIXNUM_OVERFLOW_P (n))
2443 xsignal (Qoverflow_error, list1 (string));
2444 return make_number (n);
2465} 2445}
2466 2446
2467 2447
diff --git a/src/lisp.h b/src/lisp.h
index 581835dd32b..6080007c780 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2782,7 +2782,7 @@ extern Lisp_Object oblookup (Lisp_Object, const char *, EMACS_INT, EMACS_INT);
2782 } while (0) 2782 } while (0)
2783extern int openp (Lisp_Object, Lisp_Object, Lisp_Object, 2783extern int openp (Lisp_Object, Lisp_Object, Lisp_Object,
2784 Lisp_Object *, Lisp_Object); 2784 Lisp_Object *, Lisp_Object);
2785extern int isfloat_string (const char *, int); 2785Lisp_Object string_to_float (char const *, int);
2786extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), 2786extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object),
2787 Lisp_Object); 2787 Lisp_Object);
2788extern void dir_warning (const char *, Lisp_Object); 2788extern void dir_warning (const char *, Lisp_Object);
diff --git a/src/lread.c b/src/lread.c
index d32f0b6a7e2..776d4ced7f2 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -3006,85 +3006,32 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
3006 if (!quoted && !uninterned_symbol) 3006 if (!quoted && !uninterned_symbol)
3007 { 3007 {
3008 register char *p1; 3008 register char *p1;
3009 Lisp_Object result;
3009 p1 = read_buffer; 3010 p1 = read_buffer;
3010 if (*p1 == '+' || *p1 == '-') p1++; 3011 if (*p1 == '+' || *p1 == '-') p1++;
3011 /* Is it an integer? */ 3012 /* Is it an integer? */
3012 if (p1 != p) 3013 if ('0' <= *p1 && *p1 <= '9')
3013 { 3014 {
3014 while (p1 != p && (c = *p1) >= '0' && c <= '9') p1++; 3015 do
3016 p1++;
3017 while ('0' <= *p1 && *p1 <= '9');
3018
3015 /* Integers can have trailing decimal points. */ 3019 /* Integers can have trailing decimal points. */
3016 if (p1 > read_buffer && p1 < p && *p1 == '.') p1++; 3020 p1 += (*p1 == '.');
3017 if (p1 == p) 3021 if (p1 == p)
3018 /* It is an integer. */
3019 { 3022 {
3020 if (p1[-1] == '.') 3023 /* It is an integer. */
3021 p1[-1] = '\0'; 3024 EMACS_INT n = strtol (read_buffer, NULL, 10);
3022 { 3025 if (FIXNUM_OVERFLOW_P (n))
3023 /* EMACS_INT n = atol (read_buffer); */ 3026 xsignal (Qoverflow_error,
3024 char *endptr = NULL; 3027 list1 (build_string (read_buffer)));
3025 EMACS_INT n = (errno = 0, 3028 return make_number (n);
3026 strtol (read_buffer, &endptr, 10));
3027 if (errno == ERANGE && endptr)
3028 {
3029 Lisp_Object args
3030 = Fcons (make_string (read_buffer,
3031 endptr - read_buffer),
3032 Qnil);
3033 xsignal (Qoverflow_error, args);
3034 }
3035 return make_fixnum_or_float (n);
3036 }
3037 } 3029 }
3038 } 3030 }
3039 if (isfloat_string (read_buffer, 0))
3040 {
3041 /* Compute NaN and infinities using 0.0 in a variable,
3042 to cope with compilers that think they are smarter
3043 than we are. */
3044 double zero = 0.0;
3045
3046 double value;
3047
3048 /* Negate the value ourselves. This treats 0, NaNs,
3049 and infinity properly on IEEE floating point hosts,
3050 and works around a common bug where atof ("-0.0")
3051 drops the sign. */
3052 int negative = read_buffer[0] == '-';
3053
3054 /* The only way p[-1] can be 'F' or 'N', after isfloat_string
3055 returns 1, is if the input ends in e+INF or e+NaN. */
3056 switch (p[-1])
3057 {
3058 case 'F':
3059 value = 1.0 / zero;
3060 break;
3061 case 'N':
3062 value = zero / zero;
3063 3031
3064 /* If that made a "negative" NaN, negate it. */ 3032 result = string_to_float (read_buffer, 0);
3065 3033 if (FLOATP (result))
3066 { 3034 return result;
3067 int i;
3068 union { double d; char c[sizeof (double)]; } u_data, u_minus_zero;
3069
3070 u_data.d = value;
3071 u_minus_zero.d = - 0.0;
3072 for (i = 0; i < sizeof (double); i++)
3073 if (u_data.c[i] & u_minus_zero.c[i])
3074 {
3075 value = - value;
3076 break;
3077 }
3078 }
3079 /* Now VALUE is a positive NaN. */
3080 break;
3081 default:
3082 value = atof (read_buffer + negative);
3083 break;
3084 }
3085
3086 return make_float (negative ? - value : value);
3087 }
3088 } 3035 }
3089 { 3036 {
3090 Lisp_Object name, result; 3037 Lisp_Object name, result;
@@ -3242,20 +3189,40 @@ substitute_in_interval (INTERVAL interval, Lisp_Object arg)
3242} 3189}
3243 3190
3244 3191
3192/* Return the length of the floating-point number that is the prefix of CP, or
3193 zero if there is none. */
3194
3245#define LEAD_INT 1 3195#define LEAD_INT 1
3246#define DOT_CHAR 2 3196#define DOT_CHAR 2
3247#define TRAIL_INT 4 3197#define TRAIL_INT 4
3248#define E_CHAR 8 3198#define E_CHAR 8
3249#define EXP_INT 16 3199#define EXP_INT 16
3250 3200
3251int 3201
3252isfloat_string (const char *cp, int ignore_trailing) 3202/* Convert CP to a floating point number. Return a non-float value if CP does
3203 not have valid floating point syntax. If IGNORE_TRAILING is nonzero,
3204 consider just the longest prefix of CP that has valid floating point
3205 syntax. */
3206
3207Lisp_Object
3208string_to_float (char const *cp, int ignore_trailing)
3253{ 3209{
3254 int state; 3210 int state;
3255 const char *start = cp; 3211 const char *start = cp;
3256 3212
3213 /* Compute NaN and infinities using a variable, to cope with compilers that
3214 think they are smarter than we are. */
3215 double zero = 0;
3216
3217 /* Negate the value ourselves. This treats 0, NaNs, and infinity properly on
3218 IEEE floating point hosts, and works around a formerly-common bug where
3219 atof ("-0.0") drops the sign. */
3220 int negative = *cp == '-';
3221
3222 double value = 0;
3223
3257 state = 0; 3224 state = 0;
3258 if (*cp == '+' || *cp == '-') 3225 if (negative || *cp == '+')
3259 cp++; 3226 cp++;
3260 3227
3261 if (*cp >= '0' && *cp <= '9') 3228 if (*cp >= '0' && *cp <= '9')
@@ -3295,21 +3262,43 @@ isfloat_string (const char *cp, int ignore_trailing)
3295 { 3262 {
3296 state |= EXP_INT; 3263 state |= EXP_INT;
3297 cp += 3; 3264 cp += 3;
3265 value = 1.0 / zero;
3298 } 3266 }
3299 else if (cp[-1] == '+' && cp[0] == 'N' && cp[1] == 'a' && cp[2] == 'N') 3267 else if (cp[-1] == '+' && cp[0] == 'N' && cp[1] == 'a' && cp[2] == 'N')
3300 { 3268 {
3301 state |= EXP_INT; 3269 state |= EXP_INT;
3302 cp += 3; 3270 cp += 3;
3271 value = zero / zero;
3272
3273 /* If that made a "negative" NaN, negate it. */
3274 {
3275 int i;
3276 union { double d; char c[sizeof (double)]; } u_data, u_minus_zero;
3277
3278 u_data.d = value;
3279 u_minus_zero.d = - 0.0;
3280 for (i = 0; i < sizeof (double); i++)
3281 if (u_data.c[i] & u_minus_zero.c[i])
3282 {
3283 value = - value;
3284 break;
3285 }
3286 }
3287 /* Now VALUE is a positive NaN. */
3303 } 3288 }
3304 3289
3305 return ((ignore_trailing 3290 if (! (state == (LEAD_INT|DOT_CHAR|TRAIL_INT)
3306 || *cp == 0 || *cp == ' ' || *cp == '\t' || *cp == '\n' 3291 || state == (DOT_CHAR|TRAIL_INT)
3307 || *cp == '\r' || *cp == '\f') 3292 || state == (LEAD_INT|E_CHAR|EXP_INT)
3308 && (state == (LEAD_INT|DOT_CHAR|TRAIL_INT) 3293 || state == (LEAD_INT|DOT_CHAR|TRAIL_INT|E_CHAR|EXP_INT)
3309 || state == (DOT_CHAR|TRAIL_INT) 3294 || state == (DOT_CHAR|TRAIL_INT|E_CHAR|EXP_INT)))
3310 || state == (LEAD_INT|E_CHAR|EXP_INT) 3295 return make_number (0); /* Any non-float value will do. */
3311 || state == (LEAD_INT|DOT_CHAR|TRAIL_INT|E_CHAR|EXP_INT) 3296
3312 || state == (DOT_CHAR|TRAIL_INT|E_CHAR|EXP_INT))); 3297 if (! value)
3298 value = atof (start + negative);
3299 if (negative)
3300 value = - value;
3301 return make_float (value);
3313} 3302}
3314 3303
3315 3304