//
// Copyright (C) 1991 Texas Instruments Incorporated.
//
// Permission is granted to any individual or institution to use, copy, modify,
// and distribute this software, provided that this complete copyright and
// permission notice is maintained, intact, in all copies and supporting
// documentation.
//
// Texas Instruments Incorporated provides this software "as is" without
// express or implied warranty.
//
// This file  contains  useful definitions,  macros, and constants used through
// out all  COOL header  and source files.  It is  included by Generic.h header
// file which itself is included by most other class header files.
//

#ifndef MISCELANEOUSH				// If no miscelaneous header
#define MISCELANEOUSH

#ifndef ICE_DEFSH
#include <ice_defs.h>				// Include the ice_defs header
#endif

// Not needed anymore (for now)
// #ifdef M_XENIX				// For XENIX compiler
// #define do_pack(x) #x
// #define pack(n) do_pack(pack(n))
//#endif
// Not needed anymore (for now)
// #if defined(M_XENIX)				// Get rid off const
// #define const
// #endif

#if defined(MSDOS) && !defined(DOS)		// For IBM or MS compilers
#define DOS
#endif

#ifndef INVALID					// Define INVALID for curpos
#define INVALID (-1)
#endif

#ifndef END_OF_STRING				// If END_OF_STRING not defined
#define END_OF_STRING (0)
#endif

#ifndef NEWLINE					// If Newline char not defined
#define NEWLINE '\n'
#endif

#ifndef SENSITIVE				// If case flags not defined
#define SENSITIVE TRUE
#define INSENSITIVE FALSE
#endif

#ifndef BITSPERBYTE				// Machine bits per byte macros
#define BITSPERBYTE 8
#define BITS(type) (BITSPERBYTE * (int)sizeof(type))
#define MINSHORT  ((short)(1 << BITS(short) - 1))
#define MININT  (1 << BITS(int) - 1)
#define MINLONG  (1L << BITS(long) - 1)
#define MAXSHORT ((short)~MINSHORT)
#define MAXINT  (~MININT)
#define MAXLONG (~MINLONG)
#endif

#ifndef NUMBER_STATES
#define NUMBER_STATES
enum N_status { N_OK, N_MINUS_INFINITY, N_PLUS_INFINITY, N_OVERFLOW,
		N_UNDERFLOW, N_NO_CONVERSION, N_DIVIDE_BY_ZERO };
#endif

#ifndef MAXDOUBLE
#if pdp11 || vax				// Vaxen do it their own way...
#define MAXDOUBLE	1.701411834604692293e+38
#define MAXFLOAT	((float)1.701411733192644299e+38)
/* The following is kludged because the PDP-11 compilers botch the simple form.
   The kludge causes the constant to be computed at run-time on the PDP-11,
   even though it is still "folded" at compile-time on the VAX. */
#define MINDOUBLE	(0.01 * 2.938735877055718770e-37)
#define MINFLOAT	((float)MINDOUBLE)
#define _IEEE		0
#define _DEXPLEN	8
#define _HIDDENBIT	1
#define DMINEXP	(-DMAXEXP)
#define FMINEXP	(-FMAXEXP)
#else						// IEEE floating point
#define MAXDOUBLE	1.79769313486231470e+308
#define MAXFLOAT	((float)3.40282346638528860e+38)
#define MINDOUBLE	4.94065645841246544e-324
#define MINFLOAT	((float)1.40129846432481707e-45)
#define	_IEEE		1
#define _DEXPLEN	11
#define _HIDDENBIT	1
#define DMINEXP	(-(DMAXEXP + DSIGNIF - _HIDDENBIT - 3))
#define FMINEXP	(-(FMAXEXP + FSIGNIF - _HIDDENBIT - 3))
#endif
#endif

#ifndef ABS
#define ABS(x) ((x >= 0) ? (x) : (-x))
#endif

// even --  Determine if long integer is odd of even
// Input:   long integer
// Output:  Boolean TRUE/FALSE

inline Boolean even (long n) {
  return ((n & 1) ? FALSE : TRUE);
}

// odd --  Determine if long integer is odd of even
// Input:  long integer
// Output: Boolean TRUE/FALSE

inline Boolean odd (long n) {
  return ((n & 1) ? TRUE : FALSE);
}

// The "#pragma defmacro" is a COOL extension to the standard  ANSI C processor
// that allows  a programmer to  define macro  extensions to the  language. All
// COOL  macros   have  been  incorporated  into  the preprocessor   itself  to
// facilitate extra speed and efficiency. User defined  extensions are searched
// for on the include file path.

#pragma defmacro MACRO "macro" delimiter=} recursive
#pragma defmacro template "template" delimiter=}
#pragma defmacro DECLARE "declare" delimiter=> recursive lines
#pragma defmacro IMPLEMENT "implement" delimiter=> recursive lines

// The IMPLEMENT_GENERIC macro facilitates the addition of  the virtual methods
// for a class inheriting from Generic (called from the IMPLEMENT macro).

MACRO EXPANDING IMPLEMENT_GENERIC (class) {
#if defined IMPLEMENT_GENERIC_##class && defined GENERIC_DEFINED
  ONCE_ONLY(class##_Support) {
  IMPLEMENT_GENERIC_##class();
}
#else
/* defined IMPLEMENT_GENERIC_##class && defined GENERIC_DEFINED is false */
#endif
}

// GENERATE(arg,things)s{body}
// where:
//   "things" is a comma-separated list of arguments
//   "body"   is expanded once for each thing in "things"
//   "arg"    is substituted for a "thing" while expanding "body"
//   "s"      is placed after each "body" expansion, except for the last time.
//	      useful values of "s" are nothing, a space, or a comma.
//
// The result of expanding GENERATE is the result of expanding all the "body"
// expansions with all newline's compressed out.

#pragma defmacro GENERATE generate delimiter=}

// The COMPRESS macro squeezes out the whitespace in its body argument
// #pragma defmacro COMPRESS compress delimiter=} expanding

// The ISSAME macro provides  a mechanism to  determine  if  two things are the
// same and is typically used in a #if inside a MACRO.

#pragma defmacro ISSAME "member" delimiter=) expanding

// The defmacro that defines new symbols
#pragma defmacro DEFPACKAGE_SYMBOL "define_symbol" delimiter=)

// The KEYARGS  defmacro implements a KEY argument  feature  in C++ similar to
// the &key of Common Lisp. Example:
// 
//     KEYARGS Boolean set_val (int size, KEY: int low = 0, int high = 100) {
//     :::
//     }

#if defined(unix) || defined(DOS)
#pragma defmacro KEYARGS <cool/keyargs> delimiter = )
#endif

// EXCEPTION is a cpp macro used to construct an Exception object.
// EXCEPTION has the following argument options:
//
// EXCEPTION(excp_name [, group_names] [, format_string] [rest_args])
//
// where   group_names := group_name [, group_names ]
//           rest_args := rest_arg | [, rest_arg]
//            rest_arg := format_arg | key_value_slot_arg
//          format_arg := name
//  key_value_slot_arg := name = value
//       format_string := "string"
//          group_name := SYM(name)
//          excp_name  := name
//
// In general:
//
// EXCEPTION(excp_name, SYM(group_name1), SYM(group_name2), format_string, 
//           key1=val1, arg1, key2=val2, arg2);
//
// would generate:
//
// (Exception_g = new excp_name(2, SYM(group_name1), SYM(group_name2)), 
//  Exception_g->format_msg = hprintf(ERR_MSG(format_string), 
//                                    val1, arg1, val2, arg2),
//  Exception_g->key1 = val1, 
//  Exception_g->key2 = val2, 
//  Exception_g);
//
// Note that the value of the key-val-slot-args and the non-key-val-slot-args
// are all gathered as format args for the hprintf function.  Also note that
// the key-val-slot-args and the non-key-args are intermixed.  It mainly
// depends on the format_string requirements.

#pragma defmacro EXCEPTION "exception" Exception_g format_msg set_group_names \
                 ERR_MSG hprintf delimiter=)

// THE TYPE_CASE macro is analogous to the C++ switch statment 
// It gathers all possible cases and allows the user to symbolically 
// dispatch on the type  of object  represented  by  the case statements.
//
//
//     Generic* g;
//     TYPE_CASE (g) {
//       case Vector:                // If the object is a vector
//         ....                      // Do something for Vector
//         break;
//       case List:                  // If the object is a list
//         ....                      // Do something for List
//         break;
//       default:                    // Else do the rest
//          ....
//     }
//
// expands to:
//
//     Generic* g;
//     static Symbol* switch_symbols_g[3] = {SYM(Vector), SYM(List), NULL};
//     switch (g->select_type_of(switch_symbols_g)) {
//       case 0:                     // If the object is a vector
//         ....                      // Do something for Vector
//         break;
//       case 1:                     // If the object is a list
//         ....                      // Do something for List
//         break;
//       default:                    // Else do the rest
//          ....
//     }

#pragma defmacro TYPE_CASE "typecase" delimiter=} recursive


// INITIALIZE is a macro whose body is executed once during program startup
// Example:
//   INITIALIZE (foo) {
//    initialize_foo(123);
//   }

typedef void (*initialization_function) ();
class For_Initialization_Only {	// This class exists only for its constructor
  initialization_function func;
public:
  For_Initialization_Only(initialization_function function) {
    func = function;
    (*function)();
  };
};

MACRO INITIALIZE (name, BODY: body) {
  static void Initialize_##name() {body}
  static For_Initialization_Only Initialization_For_##name \
                               (&Initialize_##name);
}

// ONCE_ONLY is a  macro that ensures that a  chunk of  code only gets compiled
// once.  It works by assigning the  default symbol value  of a symbol the file
// name where the symbol was first defined.
//
// Example:
//   ONCE_ONLY(foo) {
//    implement_foo(123);
//   }

DEFPACKAGE Once_Only_Package <once_only.p> use_first=1

#define EXPAND_ONCE_ONLY(index, symbol, type, value) value

// This  internal   macro is needed to  cause  __FILE__ to  be  expanded before
// DEFPACKAGE_SYMBOL is entered.

MACRO EXPANDING ONCE_ONLY_INTERNAL(file, symbol)
 { ISSAME(DEFPACKAGE_SYMBOL(Once_Only_Package, symbol, char*, file,,EXPAND_ONCE_ONLY), file) }

MACRO ONCE_ONLY(name, BODY: code) {
#if ONCE_ONLY_INTERNAL(__FILE__, name)
  code
#else
/* name implemented in another file */
#endif
}

// EXPAND_ARGS - how to get a macro's arguments expanded before the macro
// Example:
//    instead of:
//         va_arg(argp, Type)
//    use
//         EXPAND_ARGS(va_arg, argp, Type)
//
// If Type is something  strange like Pair<Generic*, Symbol*>, va_arg  will see
// it as two parameters instead of  one.   By expanding the arguments to va_arg
// BEFORE va_arg is invoked, the problem goes away.

MACRO EXPAND_ARGS(macro, REST: args) {EXPAND_ARGS_helper(#macro, args)}
// NOTE: #foo puts quotes around an argument, #~foo removes them.
MACRO EXPANDING EXPAND_ARGS_helper(macro, REST: args) {#~macro(args)}

// The following MACRO appends a value at the end of a #define'ed symbol
// Example:
//    #define foo
//    APPEND(foo, a)
//    APPEND(foo, b)
//    APPEND(foo, c)
//    foo
// the expansion of "foo" is a b c
//
#ifdef MACRO // Keep makedepend from complaining
MACRO APPEND(name, REST: value) {APPEND_internal(#name, name value)}
MACRO EXPANDING APPEND_internal(name, REST: rest) {
#undef  #~name
#define #~name rest}
#endif

// Use this to avoid compiler warnings when you want to ignore an argument
#define IGNORE(arg) if(&arg);

#endif MISCELANEOUSH				// End #ifdef
