LibAST Object Subsystem Design
------------------------------

 - All functions, data types, and other symbols will begin with
   "spif_" in the appropriate case.  "Spif," of course, is short for
   "Spiffy," which in turn is represented by the 'S' in "LibAST."

 - All macros will be named using uppercase ASCII characters.

 - Macros will be used for all typecasting operations.  Typecasting
   macros will be named SPIF_type(), where "type" is the capitalized
   base type name (e.g., SPIF_OBJ()).  They will take exactly one
   parameter, a variable of that type or that can be cast to that
   type.  The result will be that same parameter with the proper
   typecast applied and can subsequently be used as if it were a
   native pointer of that type.

 - Object types will be named by enclosing the base type name between
   "spif_" and "_t" (e.g., spif_obj_t).  "spif_obj_t" is actually a
   pointer to an object.  There is a corresponding type for each
   object class (e.g., spif_const_obj_t) which is the actual structure
   type.  In other words, spif_const_XXX_t is the typedef for a struct
   which contains all the member variables.  spif_XXX_t is a pointer
   to a spif_const_XXX_t.

 - Object member functions will always begin with "spif_" and the base
   type name followed by what the function does (e.g. spif_obj_new).
   All functions except for the *_new() functions will take an object
   of that type as their first parameter.  Additional parameters may
   be required for different types of functions.  Each member function
   which operates on an existing object instance will refer to that
   instance (its first parameter) as "self."

 - There are two basic object types.  The first one is
   "spif_nullobj_t."  In the strictest sense, it isn't an object at
   all.  It is merely a placeholder for objects which are
   space-sensitive.  It may not even be used.

 - The primary object type is, of course, "spif_obj_t."  This is a
   very basic type which has only those properties common to all
   types.

 - All objects should have basic methods to accomplish the following:
    - new       Allocate memory for an object (also calls init)
    - init      Initialize the object members
    - del       Deallocate memory for the object (also calls done)
    - done      Free and re-initialize object members
    - show      Convert object to a string representation
    - comp      Compare two objects of the same type
    - dup       Create an independent copy of the object
    - type      Return the string representation of the object type

 - All objects will have a corresponding "class" object which will
   contain the string representation of the class name (as specified
   by the SPIF_DECL_CNVALUE() macro) followed by a series of pointers
   to the functions above.  This externally-visible class object
   allows for basic operations to be carried out on objects of
   arbitrary/unknown type.

 - Object subclasses will be derived from their parent classes by
   declaring the first member of their structure as "parent" with the
   same type as the parent class const type.  For example, to declare
   a child class of the "obj" type, you would have "spif_const_obj_t
   parent;" as the first data member.

 - To operate on properties of the parent class, simply use the
   appropriate typecast macro (see above) to cast the pointer to the
   parent type (e.g., SPIF_OBJ(str)).

 - Some object types will not actually be defined per se, but rather
   will define abstract methods of manipulating data whose
   implementation is unimportant.  As with Java, these are referred to
   as "interface" classes.  Interface classes have a single header
   file for the interface along with a .c/.h set for each
   implementation.

 - The following should be defined for all objects (the "obj" type is
   being used as a reference):
    - SPIF_OBJ(obj)            Typecast macro
    - SPIF_OBJ_IS_OBJ(obj)     Check for type (the second OBJ)
    - SPIF_OBJ_ISNULL(obj)     Check for NULL value of instance
