#include "config.h"
/*
 - pair (of type type + one work of data (usually a pointer))
 - float
 - unknown variable (later: either Dependency, or pair, with type == Unknown)
 - special numbers (should be phazed out?)
 - Any == pair
 - Float == float
 - Variable == unknown|pair (|float|special??)
 - Number == float|special|unknown|any
 - General == Number ??
 */
/* The representation of a BIGNUM is machine dependent. For a VAX-11
 * it is as follows: 
 */
#ifndef NEWTYPE_H
#include <newtype.h>
#endif
#define ULONG_SIZE 32
#define USHORT_SIZE 16
#define CHAR_SIZE 8
#ifdef pdp10
typedef unsigned int bigdigit;
typedef long bigdouble;
#define SHIFT 		16
#define factor		1
#else
#if ((USHORT_SIZE * 2) <= ULONG_SIZE)
#define bigdigit	unsigned short
#define bigdouble	long	/* Should be unsigned */
#define SHIFT		USHORT_SIZE
#define factor		(sizeof(Pointer)/sizeof(bigdigit))
#else
#if ((CHAR_SIZE * 2) <= ULONG_SIZE)
#define bigdigit	unsigned char
#define bigdouble	long	/* Should be unsigned */
#define SHIFT		CHAR_SIZE
#define factor		(sizeof(Pointer)/sizeof(bigdigit))
#else
#include "Cannot compile bignums.  All types too large.  See bignum.h"
#endif
#endif
#endif

#ifdef IEEE_float
#define EXPONENT_LENGTH 11
#define EXPONENT_MASK 0x7FF0
#else
#define EXPONENT_LENGTH 8
#define EXPONENT_MASK 0x7F80
#endif
/* Pointer de-referencing:
 * GET(x) -- de-reference and adjust pointer
 * GET_PRE(x)
 * GET_POST(x)
 */
#ifdef LittleEndian
#define GET_PRE(p) *(p)
#define GET(p) *(p)++
#define GET_POST(p) GET(p)
#define GET_SMALLER(p) *--(p)
#define LoEndDigit(addr, length) ((unsigned char*)(addr))
#define HiEndDigit(addr, length) (LoEndDigit(addr, foo) + (length))
#else LittleEndian
#define GET(p) *--(p)
#define GET_PRE(p) GET(p)
#define GET_POST(p) *(p)
#define GET_SMALLER(p) *(p)++
#define LoEndDigit(addr, length) (HiEndDigit(addr, foo) + (length))
#define HiEndDigit(addr, length) ((unsigned char*)(addr))
#endif
#define LoEndOfBig(big) LoEndDigit((big)->first,(big)->length)
#define HiEndOfBig(big) HiEndDigit((big)->first,(big)->length)

/* Macros for manipulating long BIGNUM digits */

#define RADIX (1<<SHIFT)
#define MAX_DIGIT_SIZE (RADIX-1)
#define CARRY_MASK (MAX_DIGIT_SIZE<<SHIFT)
#define DIGIT_MASK MAX_DIGIT_SIZE
#define DIV_MASK ((1<<DELTA)-1)
#define Get_Carry(lw) (((lw & CARRY_MASK) >> SHIFT) & DIGIT_MASK)
#define Get_Digit(lw) (lw & DIGIT_MASK)
#define Mul_Radix(sw) (sw << SHIFT)
#define Div_Radix(lw) ((lw >> SHIFT) & DIV_MASK)
#define Rem_Radix(lw) (lw & DIGIT_MASK)

#define FixInt_flag 1
#define FixRat_flag 2
#define BigInt_flag 5
#define BigRat_flag 6
#define Object_flag 4
#define Complex_flag 7

union Number
  {
    double d;
    struct
      {
	unsigned sign : 1;
	unsigned exponent : EXPONENT_LENGTH;
	unsigned w1 : 31-EXPONENT_LENGTH;
	unsigned long w2;
      } x;
    struct
      {
	unsigned sign : 1;
	unsigned exponent : EXPONENT_LENGTH;
	unsigned word1 : 31-EXPONENT_LENGTH;
	unsigned char *first;
      } b;
    struct PackedRatio
      {
	unsigned sign : 1;
	unsigned exponent : EXPONENT_LENGTH;
	unsigned flag : 15-EXPONENT_LENGTH;
	unsigned short denominator;
	unsigned long numerator;
      } r;
    long i[2];
    short s[4];
    struct Any any;
  };

#define NumIsAny(num) (((num).i[0] & 0xE0000000) == 0 && (num).i[0] != 0)

struct Complex
  {
    union Number re, im;
  };

#if 0
number:
S01-------- -> float (small)
S10-------- -> float (large)
000xxxxmmmm ->type pointer or struct Any
100xxxxmmmm ->unknown variable
S111111mmmm ->special

double float: exp!=max; flag==any
infinity: e: 128 (vax)/ 2047 (ieee) [max]; w1=0, w2=0 00-
long int 01-
other NaNs w1=0, w2<>0 00-
zero: e: 0, w1: 0, w2: 0 000
packed-fraction 00-
#define NumberHasPointer(x) exp==max; firstbit(flag)==1
 /*... and hence complicates GC ... */
pointer to complex 10?
pointer to object 10?
pointer to fraction 10?
non-expandable bignum 11-
expandable bignum 11-

fraction
- each can be
-- long int
-- pointer to BigNum
complex
- each can be
-- long int
-- single float
-- pointer to Number
#endif

#define BIGALIGN 4
#define NegBigNum 0x80 /* negative */
struct BigNum
  {
#ifdef LittleEndian
    int length :24;	/* in bytes */
    unsigned char flags;
#else LittleEndian
    unsigned char flags;
    int length :24;	/* in bytes */
#endif LittleEndian
    bigdigit *first; /* hi-order word for BigEndian machines */
 /*length should multiple of BIGALIGN */
  };

#if 0
CopyBigNumToStack(big, result)
    struct BigNum *big, *result;
  { int bytes = big->bytes;
    WORD *tmp = alloca(big->bytes); /* Oops! Better be a macro! */
    result->first = tmp;
    result->last = tmp+bytes;
    result->bytes = bytes;
    bcopy(big->first, tmp, bytes);
  }
#endif

#define allocaBigNum(big, len) \
   (big)->length= (len); (big)->first = (bigdigit*)alloca((big)->length); (big)->flags= 0;
#define ZeroBigNum(big) \
  { register i = (big)->length>>2; bigdouble *ptr = (bigdouble*)(big)->first;\
    while (--i>=0) *ptr++ = 0; }
