

/* FILE: lsp.h
 *
 * declarations to use the functions in file lsp.c
 *
 *
 */

/*
 * A very simple LVAL structure to store LISPish structures.
 *
 */
typedef struct NODE
{
   unsigned char ntype; /* Type of the node. */
   union
   {
      /* when type is cons */
      struct
      {
	 struct NODE *_car,*_cdr;
      } n_cons;
      /* when type is float */
      double fvalue;
      /* when type is int or char */
      long ivalue;
      /* when type is string or symbol. */
      char *svalue;

/* ..... NO OTHER NODE TYPES ARE SUPPORTED BY THESE ROUTINES!! ..... */
   }
   n_value;
} *LVAL;


/* These functions should be defined here, 
 * before we define them as macros. */
extern LVAL car(LVAL);
extern LVAL cdr(LVAL);
/*
 * Defines for the different node types.
 */
#define NTYPE_CON 1
#define NTYPE_FLO 2
#define NTYPE_INT 3
#define NTYPE_STR 4
#define NTYPE_SYM 5
#define NTYPE_CHR 6
#define NTYPE_FRE 7 /* A special type used during freeing an list.*/

/*
 * Predicate functions (implemented as macros).
 */
#define null(x)       ((x) == NIL)
#define freep(x)      ((x)->ntype == NTYPE_FRE)
#define consp(x)      ((x)->ntype == NTYPE_CON)
#define floatp(x)     ((x)->ntype == NTYPE_FLO)
#define integerp(x)   ((x)->ntype == NTYPE_INT)
#define stringp(x)    ((x)->ntype == NTYPE_STR)
#define symbolp(x)    ((x)->ntype == NTYPE_SYM)
#define characterp(x) ((x)->ntype == NTYPE_CHR)
#define atom(x)       ((x)->ntype != NTYPE_CON)
/* Undefing floatp and integerp => numberp is safe. */
#define numberp(x)    (floatp(x)||integerp(x))
/* Synonym */
#define endp(x) null(x)
/* LISP EQ */
#define eq(x,y)   ((x)==(y))

#define evenp(x)  (!oddp(x))
#define oddp(x)   (getint(x)&1)
#define minusp(x) (floatp(x) ? getfloat(x) < 0.0 : getint(x) < 0 )
#define plusp(x)  (floatp(x) ? getfloat(x) > 0.0 : getint(x) > 0 )
#define zerop(x)  (floatp(x) ? getfloat(x) == 0.0 : getint(x) == 0 )

#define first(x)  car(x)
#define second(x) cadr(x)
#define third(x)  caddr(x)
#define fourth(x) cadddr(x)

#define listp(x)  (consp(x)||null(x))
/*
 * Access functions (implemented as macros).
 */
#define gettype(x)     ((x)->ntype)
#define car(x)         ((x)->n_value.n_cons._car)
#define cdr(x)         ((x)->n_value.n_cons._cdr)
#define getstring(x)   ((x)->n_value.svalue)
#define getint(x)      ((x)->n_value.ivalue)
#define getfloat(x)    ((x)->n_value.fvalue)
#define getchr(x)      getint(x)
#define getsymbol(x)   getstring(x)

/* Definitions like:
    #define caar(x) ((((x)->n_value.n_cons._car))->n_value.n_cons._car)
   would make the usage of caar unsafe. If the definition is car(car(x))
   then undefing car and cdr the macro caar and cadr and the others became
   safe, calling the functions instead of the macro.

   These are all the functions that are implemented in XLISP.
*/
#define caar(x) car(car(x))
#define cadr(x) car(cdr(x))
#define cdar(x) cdr(car(x))
#define cddr(x) cdr(cdr(x))

#define caaar(x) car(car(car(x)))
#define caadr(x) car(car(cdr(x)))
#define cadar(x) car(cdr(car(x)))
#define caddr(x) car(cdr(cdr(x)))
#define cdaar(x) cdr(car(car(x)))
#define cdadr(x) cdr(car(cdr(x)))
#define cddar(x) cdr(cdr(car(x)))
#define cdddr(x) cdr(cdr(cdr(x)))

#define caaaar(x) car(car(car(car(x))))
#define caaadr(x) car(car(car(cdr(x))))
#define caadar(x) car(car(cdr(car(x))))
#define caaddr(x) car(car(cdr(cdr(x))))
#define cadaar(x) car(cdr(car(car(x))))
#define cadadr(x) car(cdr(car(cdr(x))))
#define caddar(x) car(cdr(cdr(car(x))))
#define cadddr(x) car(cdr(cdr(cdr(x))))
#define cdaaar(x) cdr(car(car(car(x))))
#define cdaadr(x) cdr(car(car(cdr(x))))
#define cdadar(x) cdr(car(cdr(car(x))))
#define cdaddr(x) cdr(car(cdr(cdr(x))))
#define cddaar(x) cdr(cdr(car(car(x))))
#define cddadr(x) cdr(cdr(car(cdr(x))))
#define cdddar(x) cdr(cdr(cdr(car(x))))
#define cddddr(x) cdr(cdr(cdr(cdr(x))))

/*
 * Field setting functions (implemented as macros.
 */
#define settype(x,v)    ((x)->ntype=(v))
#define setcar(x,v)     ((x)->n_value.n_cons._car=(v))
#define setcdr(x,v)     ((x)->n_value.n_cons._cdr=(v))
#define setint(x,v)     ((x)->n_value.ivalue=(v))
#define setfloat(x,v)   ((x)->n_value.fvalue=(v))
#define setstring(x,v)  ((x)->n_value.svalue=(v))
#define setchar(x,v)    setint(x,v)
#define setsymbol(x,v)  setstring(x,v)

/*
 *  sassoc is a special case of nthsassoc
 */
#define sassoc(x,y) nthsassoc((x),(y),1)


/*
 * A LISP like looping constructs.
 * (z is a help variable)
 */
#define dolist(X,Y,z) for( X= (z=Y)      ? car(z) : NIL ; z ; \
                           X= (z=cdr(z)) ? car(z) : NIL )

/* Well, one may like these.
 */
#define dotimes(i,x) for(i = 0 ; i < x ; i++ )
#define loop         for(;;)
/*
 * Creating functions (implemented as macros).
 */
#define newstring()  newnode(NTYPE_STR)
#define newsymbol()  newnode(NTYPE_SYM)
#define newint()     newnode(NTYPE_INT)
#define newfloat()   newnode(NTYPE_FLO)
#define newchar()    newnode(NTYPE_CHR)
/*
 * Define the most important symbol of LISP
 */
#define NIL (LVAL)0

/*
 * Define the width of the screen for pprinting.
 */
#define SCR_WIDTH 70
/*
 * Define the maximal length of a string.
 */
#define MAXSTRING 100
/*
 * Printing length of too long strings in error messages
 */
#define ERRSTRLEN 5
/*
 * Define function prototypes.
 */
extern LVAL cons(void);
extern LVAL newnode(unsigned char);
extern LVAL freelist(LVAL);
extern LVAL pprint(LVAL, FILE *);
extern LVAL readcons(FILE *);
extern LVAL readlist(FILE *);
extern LVAL readexpr(FILE *);
extern LVAL skipexpr(FILE *);
extern LVAL setflags(int, int);
extern LVAL symcmp(LVAL, char *);
extern LVAL nthsassoc(LVAL, char *, int);
extern LVAL nth(int, LVAL);
extern LVAL nthcdr(int, LVAL);
extern LVAL char_code(LVAL);
extern LVAL char_downcase(LVAL);
extern LVAL char_upcase(LVAL);
extern int equal(LVAL, LVAL);
extern int  llength(LVAL);
/**/
extern char *StrDup(char *);
