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.

Reply via email to