Port NaN, infinity handling better to VAX

Nowadays .elc files routinely contain tokens like 1.0e+INF and
0.0e+NaN that do not work on antiques like the VAX that lack IEEE fp.
Port Emacs to these platforms, by treating infinities as extreme
values and NaNs as strings that trap if used numerically.
* src/lread.c (INFINITY): Default to HUGE_VAL if non-IEEE.
(not_a_number) [!IEEE_FLOATING_POINT]: New static array.
(syms_of_lread) [!IEEE_FLOATING_POINT]: Initialize it.
(read0): Report invalid syntax for +0.0e+NaN on platforms
that lack NaNs.
(string_to_number): On non-IEEE platforms, return HUGE_VAL
for infinity and a string for NaN.  All callers changed.
This commit is contained in:
Paul Eggert 2023-07-13 14:26:29 -07:00
parent b94e7e6334
commit 0cd519971d
5 changed files with 44 additions and 9 deletions

View file

@ -270,10 +270,6 @@ two NaNs as equal when their
signs and significands agree. Significands of NaNs are
machine-dependent, as are the digits in their string representation.
NaNs are not available on systems which do not use IEEE
floating-point arithmetic; if the read syntax for a NaN is used on a
VAX, for example, the reader signals an error.
When NaNs and signed zeros are involved, non-numeric functions like
@code{eql}, @code{equal}, @code{sxhash-eql}, @code{sxhash-equal} and
@code{gethash} determine whether values are indistinguishable, not
@ -283,6 +279,12 @@ whether they are numerically equal. For example, when @var{x} and
conversely, @code{(equal 0.0 -0.0)} returns @code{nil} whereas
@code{(= 0.0 -0.0)} returns @code{t}.
Infinities and NaNs are not available on legacy systems that lack
IEEE floating-point arithmetic. On a circa 1980 VAX, for example, the
Lisp reader approximates an infinity with the nearest finite value,
and a NaN with some other non-numeric Lisp object that provokes an
error if used numerically.
Here are read syntaxes for these special floating-point values:
@table @asis

View file

@ -585,6 +585,14 @@ behavior back for any other reason, you can do that using the
previous behavior of showing 'U' in the mode line for 'koi8-u':
(coding-system-put 'koi8-u :mnemonic ?U)
+++
** Infinities and NaNs no longer act as symbols on non-IEEE platforms.
On old platforms like the VAX that do not support IEEE floating-point,
tokens like 0.0e+NaN and 1.0e+INF are no longer read as symbols.
Instead, the Lisp reader approximates an infinity with the nearest
finite value, and a NaN with some other non-numeric object that
provokes an error if used numerically.
* Lisp Changes in Emacs 30.1

View file

@ -3033,7 +3033,8 @@ If the base used is not 10, STRING is always parsed as an integer. */)
p++;
Lisp_Object val = string_to_number (p, b, 0);
return NILP (val) ? make_fixnum (0) : val;
return ((IEEE_FLOATING_POINT ? NILP (val) : !NUMBERP (val))
? make_fixnum (0) : val);
}
enum arithop

View file

@ -75,6 +75,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
# ifndef INFINITY
# define INFINITY ((union ieee754_double) {.ieee = {.exponent = -1}}.d)
# endif
#else
# ifndef INFINITY
# define INFINITY HUGE_VAL
# endif
#endif
/* The objects or placeholders read with the #n=object form.
@ -4477,10 +4481,17 @@ substitute_in_interval (INTERVAL interval, void *arg)
}
#if !IEEE_FLOATING_POINT
/* Strings that stand in for +NaN, -NaN, respectively. */
static Lisp_Object not_a_number[2];
#endif
/* Convert the initial prefix of STRING to a number, assuming base BASE.
If the prefix has floating point syntax and BASE is 10, return a
nearest float; otherwise, if the prefix has integer syntax, return
the integer; otherwise, return nil. If PLEN, set *PLEN to the
the integer; otherwise, return nil. (On antique platforms that lack
support for NaNs, if the prefix has NaN syntax return a Lisp object that
will provoke an error if used as a number.) If PLEN, set *PLEN to the
length of the numeric prefix if there is one, otherwise *PLEN is
unspecified. */
@ -4545,7 +4556,6 @@ string_to_number (char const *string, int base, ptrdiff_t *plen)
cp++;
while ('0' <= *cp && *cp <= '9');
}
#if IEEE_FLOATING_POINT
else if (cp[-1] == '+'
&& cp[0] == 'I' && cp[1] == 'N' && cp[2] == 'F')
{
@ -4558,12 +4568,17 @@ string_to_number (char const *string, int base, ptrdiff_t *plen)
{
state |= E_EXP;
cp += 3;
#if IEEE_FLOATING_POINT
union ieee754_double u
= { .ieee_nan = { .exponent = 0x7ff, .quiet_nan = 1,
.mantissa0 = n >> 31 >> 1, .mantissa1 = n }};
value = u.d;
}
#else
if (plen)
*plen = cp - string;
return not_a_number[negative];
#endif
}
else
cp = ecp;
}
@ -5707,6 +5722,14 @@ that are loaded before your customizations are read! */);
DEFSYM (Qcomma, ",");
DEFSYM (Qcomma_at, ",@");
#if !IEEE_FLOATING_POINT
for (int negative = 0; negative < 2; negative++)
{
not_a_number[negative] = build_pure_c_string (&"-0.0e+NaN"[!negative]);
staticpro (&not_a_number[negative]);
}
#endif
DEFSYM (Qinhibit_file_name_operation, "inhibit-file-name-operation");
DEFSYM (Qascii_character, "ascii-character");
DEFSYM (Qfunction, "function");

View file

@ -7130,7 +7130,8 @@ See function `signal-process' for more details on usage. */)
{
ptrdiff_t len;
tem = string_to_number (SSDATA (process), 10, &len);
if (NILP (tem) || len != SBYTES (process))
if ((IEEE_FLOATING_POINT ? NILP (tem) : !NUMBERP (tem))
|| len != SBYTES (process))
return Qnil;
}
process = tem;