aboutsummaryrefslogtreecommitdiffstats
path: root/src/lread.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lread.c')
-rw-r--r--src/lread.c149
1 files changed, 69 insertions, 80 deletions
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