The C++ standard says
If during the evaluation of an expression, the result is not mathemat-
ically defined or not in the range of representable values for its
type, the behavior is undefined ...
Assuming the same holds for C (I don't know where the C standard is),
the following:
#define isSmall(c) (INTMIN<=(c)
Cell mkInt(n) /* make cell representing integer */
Int n; {
return isSmall(INTZERO+n) ? INTZERO+n : pair(INTCELL,n);
}
results in undefined behavior if n is large enough to cause an
overflow. For this code to work, INTZERO + n needs to be evaluated
with silent overflow, then the <= comparison done. However, a
compiler would be within its rights (because overflow results in
undefined behavior) to optimize this to (INTMIN - INTZERO) <= n which
doesn't give the desired result.
Rewriting mkInt() to:
Cell mkInt(n) /* make cell representing integer */
Int n; {
/*
* Was:
* return isSmall(INTZERO+n) ? INTZERO+n : pair(INTCELL,n);
*/
const int minSmallInt = INTMIN - INTZERO;
const int maxSmallInt = INTMAX - INTZERO;
return (minSmallInt <= n) && (n <= maxSmallInt) ? INTZERO+n
: pair(INTCELL,n);
}
fixes my problems with large (but not BIGNUM) integers and should be
portable. Here's Hugs with the original mkInt():
Main> 0x7fffffff
INTERNAL ERROR: in depExpr
and with my mkInt() above:
Prelude> 0x7fffffff
2147483647
I can't think of a portable way to get at the silent-overflow two's
complement arithmetic that most computers have in C. Is there one?
mike
P.S. I had to (filter (/= '\r')) parser.c to get it to compile.