[net.sources] xlisp2.txt - new xlisp release

betz (04/01/83)

<<<<<<<<<< xlio.c >>>>>>>>>>
/* xlio - xlisp i/o routines */

#include <stdio.h>
#include "xlisp.h"

/* global variables */
int (*xlgetc)();
int xlpvals;
int xlplevel;

/* local variables */
static int prompt;
static FILE *ifp;

/* tgetc - get a character from the terminal */
static int tgetc()
{
    int ch;

    /* prompt if necessary */
    if (prompt) {
	if (xlplevel > 0)
	    printf("%d> ",xlplevel);
	else
	    printf("> ");
	prompt = FALSE;
    }

    /* get the character */
    if ((ch = getchar()) == '\n')
	prompt = TRUE;

    /* return the character */
    return (ch);
}

/* xltin - setup terminal input */
int xltin(flag)
  int flag;
{
    /* flush line if flag is set */
    if (flag & !prompt)
	while (tgetc() != '\n')
	    ;

    /* initialize */
    prompt = TRUE;
    xlplevel = 0;
    xlgetc = tgetc;
    xlpvals = TRUE;
}

/* fgetcx - get a character from a file */
static int fgetcx()
{
    int ch;

    /* get a character */
    if ((ch = getc(ifp)) <= 0) {
	xlgetc = tgetc;
	xlpvals = TRUE;
	return (tgetc());
    }

    /* return it */
    return (ch);
}

/* xlfin - setup file input */
xlfin(str)
  char *str;
{
#ifdef DEFEXT
    char fname[100];

    /* create the file name */
    strcpy(fname,str);

    /* check for extension */
    if (strchr(fname,'.') == 0)
	strcat(fname,".lsp");
#else
#define fname str
#endif

    /* open the input file */
    if ((ifp = fopen(fname,"r")) == NULL) {
	printf("can't open \"%s\" for input\n",fname);
	return;
    }

    /* setup input from the file */
    xlgetc = fgetcx;
    xlpvals = FALSE;
}
<<<<<<<<<< xlisp.c >>>>>>>>>>
/* xlisp - a small subset of lisp */

#include <stdio.h>
#include <setjmp.h>
#include "xlisp.h"

/* global variables */
jmp_buf xljmpbuf;

/* external variables */
extern struct node *xlenv;
extern struct node *xlstack;
extern int xlpvals;

/* main - the main routine */
main(argc,argv)
  int argc; char *argv[];
{
    struct node expr;

    /* initialize the dynamic memory module (must be first) */
    xldmeminit();

    /* initialize xlisp */
    xlinit();
    xleinit(); xllinit(); xlminit();
    xloinit(); xlsinit(); xlfinit();
    xlpinit(); xlkinit();

    /* initialize terminal input */
    xltin(FALSE);

    /* read the input file if specified */
    if (argc > 1)
	xlfin(argv[1]);
    else
	printf("XLISP version 1.0\n");

    /* main command processing loop */
    while (TRUE) {

	/* setup the error return */
	setjmp(xljmpbuf);

	/* free any previous expression and leftover context */
	xlstack = xlenv = NULL;

	/* create a new stack frame */
	xlsave(&expr,NULL);

	/* read an expression */
	expr.n_ptr = xlread();

	/* evaluate the expression */
	expr.n_ptr = xleval(expr.n_ptr);

	/* print it if necessary */
	if (xlpvals) {
	    xlprint(expr.n_ptr,TRUE);
	    putchar('\n');
	}
    }
}
<<<<<<<<<< xlkmap.c >>>>>>>>>>
/* xlkmap - xlisp key map functions */

#include <stdio.h>
#include "xlisp.h"

/* external variables */
extern struct node *xlstack;
extern struct node *xlenv;
extern struct node *self;

/* local definitions */
#define KMSIZE	256	/* number of characters in a keymap */
#define KMAX	20	/* maximum number of characters in a key sequence */
#define KEYMAP	0	/* instance variable number for 'keymap' */

/* local variables */
static struct node *currentenv;

/* forward declarations (the extern hack is because of decusc) */
extern struct node *sendmsg();

/* isnew - initialize a new keymap */
static struct node *isnew(args)
  struct node *args;
{
    /* make sure there aren't any arguments */
    xllastarg(args);

    /* create a keymap node */
    xlivar(self->n_symvalue,KEYMAP)->n_listvalue = newnode(KMAP);

    /* return the keymap object */
    return (self->n_symvalue);
}

/* newkmap - allocate memory for a new key map vector */
static struct node *(*newkmap())[]
{
    struct node *(*map)[];

    /* allocate the vector */
    if ((map = (struct node *(*)[]) calloc(1,sizeof(struct node *) * KMSIZE))
    			 == NULL) {
	printf("insufficient memory");
	exit();
    }

    /* return the new vector */
    return (map);
}

/* key - define a key */
static struct node *key(args)
  struct node *args;
{
    struct node *oldstk,arg,kstr,ksym,*kmap,*kmptr;
    struct node *(*map)[];
    char *sptr;
    int ch;

    /* create a new stack frame */
    oldstk = xlsave(&arg,&kstr,&ksym,NULL);

    /* initialize */
    arg.n_ptr = args;

    /* get the keymap */
    kmap = xlivar(self->n_symvalue,KEYMAP)->n_listvalue;
    if (kmap == NULL && kmap->n_type != KMAP)
	xlfail("bad keymap object");

    /* get the key string */
    kstr.n_ptr = xlevmatch(STR,&arg.n_ptr);

    /* get the key symbol */
    ksym.n_ptr = xlevmatch(SYM,&arg.n_ptr);

    /* make sure there aren't any more arguments */
    xllastarg(arg.n_ptr);

    /* process each character in the key string */
    for (kmptr = kmap, sptr = kstr.n_ptr->n_str;
    	 *sptr != 0;
    	 kmptr = (*map)[ch]) {

	/* get a character */
	ch = *sptr++;

	/* allocate a key map vector if non currently exists */
	if ((map = kmptr->n_kmap) == NULL)
	    map = kmptr->n_kmap = newkmap();

	/* check for this being the last character in the string */
	if (*sptr == 0)
	    (*map)[ch] = ksym.n_ptr;
	else
	    if ((*map)[ch] == NULL || (*map)[ch]->n_type != KMAP) {
		(*map)[ch] = newnode(KMAP);
		(*map)[ch]->n_kmap = newkmap();
	    }
    }

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the keymap object */
    return (self->n_symvalue);
}

/* process - process input characters using a key map */
static struct node *process(args)
  struct node *args;
{
    struct node *oldstk,arg,env,margs,*kmap,*kmptr,*nptr,*oldenv;
    struct node *(*map)[];
    char keys[KMAX+1];
    int ch,kndx;

    /* create a new stack frame */
    oldstk = xlsave(&arg,&env,&margs,NULL);

    /* initialize */
    arg.n_ptr = args;

    /* get the keymap */
    kmap = xlivar(self->n_symvalue,KEYMAP)->n_listvalue;
    if (kmap == NULL && kmap->n_type != KMAP)
	xlfail("bad keymap object");

    /* get the environment */
    env.n_ptr = xlevmatch(LIST,&arg.n_ptr);

    /* make sure there aren't any more arguments */
    xllastarg(arg.n_ptr);

    /* bind the current environment variable */
    oldenv = xlenv;
    xlbind(currentenv,env.n_ptr);
    xlfixbindings(oldenv);

    /* make sure the key map is defined */
    if (kmap->n_kmap == NULL)
	xlfail("empty keymap");

    /* create an argument list to send with key messages */
    margs.n_ptr = newnode(LIST);
    margs.n_ptr->n_listvalue = newnode(STR);
    margs.n_ptr->n_listvalue->n_str = keys;
    margs.n_ptr->n_listvalue->n_strtype = STATIC;

    /* character processing loop */
    for (kmptr = kmap, kndx = 0; TRUE; ) {

	/* flush pending output */
	fflush(stdout);

	/* get a character */
	if ((ch = kbin()) < 0)
	    break;

	/* put it in the key sequence */
	if (kndx < KMAX)
	    keys[kndx++] = ch;
	else
	    xlfail("key sequence too long");

	/* dispatch on character code */
	if ((map = kmptr->n_kmap) == NULL)
	    xlfail("bad keymap");
	else if ((nptr = (*map)[ch]) == NULL) {
	    kmptr = kmap;
	    kndx = 0;
	}
	else if (nptr->n_type == KMAP)
	    kmptr = (*map)[ch];
	else if (nptr->n_type == SYM) {
	    keys[kndx] = 0;
	    if (sendmsg(nptr,currentenv->n_symvalue,margs.n_ptr) == NULL)
		break;
	    kmptr = kmap;
	    kndx = 0;
	}
	else
	    xlfail("bad keymap");
    }

    /* unbind */
    xlunbind(oldenv);

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the keymap object */
    return (self->n_symvalue);
}

/* sendmsg - send a message given an environment list */
static struct node *sendmsg(msym,env,args)
  struct node *msym,*env,*args;
{
    struct node *eptr,*obj,*msg;

    /* look for an object that answers the message */
    for (eptr = env; eptr != NULL; eptr = eptr->n_listnext)
	if ((obj = eptr->n_listvalue) != NULL && obj->n_type == OBJ)
	    if ((msg = xlmfind(obj,msym)) != NULL)
		return (xlxsend(obj,msg,args));

    /* return the message if no object answered it */
    return (msym);
}

/* xlkmmark - mark a keymap */
xlkmmark(km)
  struct node *km;
{
    struct node *(*map)[];
    int i;

    /* mark the keymap node */
    km->n_flags |= MARK;

    /* check for a null keymap */
    if ((map = km->n_kmap) == NULL)
	return;

    /* loop through each keymap entry */
    for (i = 0; i < KMSIZE; i++)
	if (((*map)[i] != NULL) && (*map)[i]->n_type == KMAP)
	    xlkmmark((*map)[i]);
}

/* xlkmfree - free a keymap */
xlkmfree(km)
  struct node *km;
{
    struct node *(*map)[];
    int i;

    /* check for a null keymap */
    if ((map = km->n_kmap) == NULL)
	return;

    /* loop through each keymap entry */
    for (i = 0; i < KMSIZE; i++)
	if (((*map)[i] != NULL) && (*map)[i]->n_type == KMAP)
	    xlkmfree((*map)[i]);

    /* free this keymap */
    free(km->n_kmap);
}

/* xlkinit - key map function initialization routine */
xlkinit()
{
    struct node *keymap;

    /* define the xlisp variables */
    currentenv = xlenter("currentenv");

    /* define the keymap class */
    keymap = xlclass("Keymap",1);
    xladdivar(keymap,"keymap");
    xladdmsg(keymap,"isnew",isnew);
    xladdmsg(keymap,"key",key);
    xladdmsg(keymap,"process",process);
}
<<<<<<<<<< xllist.c >>>>>>>>>>
/* xllist - xlisp list builtin functions */

#include <stdio.h>
#include "xlisp.h"

/* external variables */
extern struct node *xlstack;

/* local variables */
static struct node *t;

/* xlist - builtin function list */
static struct node *xlist(args)
  struct node *args;
{
    struct node *oldstk,arg,list,val,*last,*lptr;

    /* create a new stack frame */
    oldstk = xlsave(&arg,&list,&val,NULL);

    /* initialize */
    arg.n_ptr = args;

    /* evaluate and append each argument */
    for (last = NULL; arg.n_ptr != NULL; last = lptr) {

	/* evaluate the next argument */
	val.n_ptr = xlevarg(&arg.n_ptr);

	/* append this argument to the end of the list */
	lptr = newnode(LIST);
	if (last == NULL)
	    list.n_ptr = lptr;
	else
	    last->n_listnext = lptr;
	lptr->n_listvalue = val.n_ptr;
    }

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the list */
    return (list.n_ptr);
}

/* cond - builtin function cond */
static struct node *cond(args)
  struct node *args;
{
    struct node *oldstk,arg,list,*val;

    /* create a new stack frame */
    oldstk = xlsave(&arg,&list,NULL);

    /* initialize */
    arg.n_ptr = args;

    /* initialize the return value */
    val = NULL;

    /* find a predicate that is true */
    while (arg.n_ptr != NULL) {

	/* get the next conditional */
	list.n_ptr = xlmatch(LIST,&arg.n_ptr);

	/* evaluate the predicate part */
	if (xlevarg(&list.n_ptr) != NULL) {

	    /* evaluate each expression */
	    while (list.n_ptr != NULL)
		val = xlevarg(&list.n_ptr);

	    /* exit the loop */
	    break;
	}
    }

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the value */
    return (val);
}

/* atom - is this an atom? */
static struct node *atom(args)
  struct node *args;
{
    struct node *arg;

    /* get the argument */
    if ((arg = xlevarg(&args)) == NULL || arg->n_type != LIST)
	return (t);
    else
	return (NULL);
}

/* null - is this null? */
static struct node *null(args)
  struct node *args;
{
    /* get the argument */
    if (xlevarg(&args) == NULL)
	return (t);
    else
	return (NULL);
}

/* listp - is this a list? */
static struct node *listp(args)
  struct node *args;
{
    /* get the argument */
    if (xlistp(xlevarg(&args)))
	return (t);
    else
	return (NULL);
}

/* xlistp - internal listp function */
static int xlistp(arg)
  struct node *arg;
{
    return (arg == NULL || arg->n_type == LIST);
}

/* eq - are these equal? */
static struct node *eq(args)
  struct node *args;
{
    struct node *oldstk,arg,arg1,arg2,*val;

    /* create a new stack frame */
    oldstk = xlsave(&arg,&arg1,&arg2,NULL);

    /* initialize */
    arg.n_ptr = args;

    /* first argument */
    arg1.n_ptr = xlevarg(&arg.n_ptr);

    /* second argument */
    arg2.n_ptr = xlevarg(&arg.n_ptr);

    /* make sure there aren't any more arguments */
    xllastarg(arg.n_ptr);

    /* compare the arguments */
    if (xeq(arg1.n_ptr,arg2.n_ptr))
	val = t;
    else
	val = NULL;

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the result */
    return (val);
}

/* xeq - internal eq function */
static int xeq(arg1,arg2)
  struct node *arg1,*arg2;
{
    /* compare the arguments */
    if (arg1 != NULL && arg1->n_type == INT &&
    	arg2 != NULL && arg2->n_type == INT)
	return (arg1->n_int == arg2->n_int);
    else
	return (arg1 == arg2);
}

/* equal - are these equal? */
static struct node *equal(args)
  struct node *args;
{
    struct node *oldstk,arg,arg1,arg2,*val;

    /* create a new stack frame */
    oldstk = xlsave(&arg,&arg1,&arg2,NULL);

    /* initialize */
    arg.n_ptr = args;

    /* first argument */
    arg1.n_ptr = xlevarg(&arg.n_ptr);

    /* second argument */
    arg2.n_ptr = xlevarg(&arg.n_ptr);

    /* make sure there aren't any more arguments */
    xllastarg(arg.n_ptr);

    /* compare the arguments */
    if (xequal(arg1.n_ptr,arg2.n_ptr))
	val = t;
    else
	val = NULL;

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the result */
    return (val);
}

/* xequal - internal equal function */
static int xequal(arg1,arg2)
  struct node *arg1,*arg2;
{
    /* compare the arguments */
    if (xeq(arg1,arg2))
	return (TRUE);
    else if (xlistp(arg1) && xlistp(arg2))
	return (xequal(arg1->n_listvalue,arg2->n_listvalue) &&
		xequal(arg1->n_listnext, arg2->n_listnext));
    else
	return (FALSE);
}

/* head - return the head of a list */
static struct node *head(args)
  struct node *args;
{
    struct node *list;

    /* get the list */
    if ((list = xlevmatch(LIST,&args)) == NULL)
	xlfail("null list");

    /* make sure this is the only argument */
    xllastarg(args);

    /* return the head of the list */
    return (list->n_listvalue);
}

/* tail - return the tail of a list */
static struct node *tail(args)
  struct node *args;
{
    struct node *list;

    /* get the list */
    if ((list = xlevmatch(LIST,&args)) == NULL)
	xlfail("null list");

    /* make sure this is the only argument */
    xllastarg(args);

    /* return the tail of the list */
    return (list->n_listnext);
}

/* nth - return the nth element of a list */
static struct node *nth(args)
  struct node *args;
{
    struct node *oldstk,arg,list;
    int n;

    /* create a new stack frame */
    oldstk = xlsave(&arg,&list,NULL);

    /* initialize */
    arg.n_ptr = args;

    /* get n */
    if ((n = xlevmatch(INT,&arg.n_ptr)->n_int) < 1)
	xlfail("invalid argument");

    /* get the list */
    if ((list.n_ptr = xlevmatch(LIST,&arg.n_ptr)) == NULL)
	xlfail("invalid argument");

    /* make sure this is the only argument */
    xllastarg(arg.n_ptr);

    /* find the nth element */
    for (; n > 1; n--) {
	list.n_ptr = list.n_ptr->n_listnext;
	if (list.n_ptr == NULL || list.n_ptr->n_type != LIST)
	    xlfail("invalid argument");
    }

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the list nth list element */
    return (list.n_ptr->n_listvalue);
}

/* length - return the length of a list */
static struct node *length(args)
  struct node *args;
{
    struct node *oldstk,list,*val;
    int n;

    /* create a new stack frame */
    oldstk = xlsave(&list,NULL);

    /* get the list */
    list.n_ptr = xlevmatch(LIST,&args);

    /* make sure this is the only argument */
    xllastarg(args);

    /* find the length */
    for (n = 0; list.n_ptr != NULL; n++)
	list.n_ptr = list.n_ptr->n_listnext;

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* create the value node */
    val = newnode(INT);
    val->n_int = n;

    /* return the length */
    return (val);
}

/* append - builtin function append */
static struct node *append(args)
  struct node *args;
{
    struct node *oldstk,arg,list,last,val,*lptr;

    /* create a new stack frame */
    oldstk = xlsave(&arg,&list,&last,&val,NULL);

    /* initialize */
    arg.n_ptr = args;

    /* evaluate and append each argument */
    while (arg.n_ptr != NULL) {

	/* evaluate the next argument */
	list.n_ptr = xlevmatch(LIST,&arg.n_ptr);

	/* append each element of this list to the result list */
	while (list.n_ptr != NULL && list.n_ptr->n_type == LIST) {

	    /* append this element */
	    lptr = newnode(LIST);
	    if (last.n_ptr == NULL)
		val.n_ptr = lptr;
	    else
		last.n_ptr->n_listnext = lptr;
	    lptr->n_listvalue = list.n_ptr->n_listvalue;

	    /* save the new last element */
	    last.n_ptr = lptr;

	    /* move to the next element */
	    list.n_ptr = list.n_ptr->n_listnext;
	}

	/* make sure the list ended in a nil */
	if (list.n_ptr != NULL)
	    xlfail("bad list");
    }

    /* restore previous stack frame */
    xlstack = oldstk;

    /* return the list */
    return (val.n_ptr);
}

/* reverse - builtin function reverse */
static struct node *reverse(args)
  struct node *args;
{
    struct node *oldstk,list,val,*lptr;

    /* create a new stack frame */
    oldstk = xlsave(&list,&val,NULL);

    /* get the list to reverse */
    list.n_ptr = xlevmatch(LIST,&args);

    /* make sure there aren't any more arguments */
    xllastarg(args);

    /* append each element of this list to the result list */
    while (list.n_ptr != NULL && list.n_ptr->n_type == LIST) {

	/* append this element */
	lptr = newnode(LIST);
	lptr->n_listvalue = list.n_ptr->n_listvalue;
	lptr->n_listnext = val.n_ptr;
	val.n_ptr = lptr;

	/* move to the next element */
	list.n_ptr = list.n_ptr->n_listnext;
    }

    /* make sure the list ended in a nil */
    if (list.n_ptr != NULL)
	xlfail("bad list");

    /* restore previous stack frame */
    xlstack = oldstk;

    /* return the list */
    return (val.n_ptr);
}

/* cons - construct a new list cell */
static struct node *cons(args)
  struct node *args;
{
    struct node *oldstk,arg,arg1,arg2,*lptr;

    /* create a new stack frame */
    oldstk = xlsave(&arg,&arg1,&arg2,NULL);

    /* initialize */
    arg.n_ptr = args;

    /* first argument */
    arg1.n_ptr = xlevarg(&arg.n_ptr);

    /* second argument */
    arg2.n_ptr = xlevarg(&arg.n_ptr);

    /* make sure there aren't any more arguments */
    xllastarg(arg.n_ptr);

    /* construct a new list element */
    lptr = newnode(LIST);
    lptr->n_listvalue = arg1.n_ptr;
    lptr->n_listnext  = arg2.n_ptr;

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the list */
    return (lptr);
}

/* xllinit - xlisp list initialization routine */
xllinit()
{
    /* define some symbols */
    t = xlenter("t");

    /* functions with reasonable names */
    xlsubr("head",head);
    xlsubr("tail",tail);
    xlsubr("nth",nth);

    /* real lisp functions */
    xlsubr("atom",atom);
    xlsubr("eq",eq);
    xlsubr("equal",equal);
    xlsubr("null",null);
    xlsubr("listp",listp);
    xlsubr("cond",cond);
    xlsubr("list",xlist);
    xlsubr("cons",cons);
    xlsubr("car",head);
    xlsubr("cdr",tail);
    xlsubr("append",append);
    xlsubr("reverse",reverse);
    xlsubr("length",length);
}
<<<<<<<<<< xlmath.c >>>>>>>>>>
/* xlmath - xlisp builtin arithmetic functions */

#include <stdio.h>
#include "xlisp.h"

/* external variables */
extern struct node *xlstack;

/* local variables */
static struct node *true;

/* forward declarations (the extern hack is for decusc) */
extern struct node *arith();
extern struct node *compare();

/* add - builtin function for addition */
static int xadd(val,arg)
  int val,arg;
{
    return (val + arg);
}
static struct node *add(args)
  struct node *args;
{
    return (arith(args,xadd));
}

/* sub - builtin function for subtraction */
static int xsub(val,arg)
  int val,arg;
{
    return (val - arg);
}
static struct node *sub(args)
  struct node *args;
{
    return (arith(args,xsub));
}

/* mul - builtin function for multiplication */
static int xmul(val,arg)
  int val,arg;
{
    return (val * arg);
}
static struct node *mul(args)
  struct node *args;
{
    return (arith(args,xmul));
}

/* div - builtin function for division */
static int xdiv(val,arg)
  int val,arg;
{
    return (val / arg);
}
static struct node *div(args)
  struct node *args;
{
    return (arith(args,xdiv));
}

/* mod - builtin function for modulus */
static int xmod(val,arg)
  int val,arg;
{
    return (val % arg);
}
static struct node *mod(args)
  struct node *args;
{
    return (arith(args,xmod));
}

/* and - builtin function for modulus */
static int xand(val,arg)
  int val,arg;
{
    return (val & arg);
}
static struct node *and(args)
  struct node *args;
{
    return (arith(args,xand));
}

/* or - builtin function for modulus */
static int xor(val,arg)
  int val,arg;
{
    return (val | arg);
}
static struct node *or(args)
  struct node *args;
{
    return (arith(args,xor));
}

/* not - bitwise not */
static struct node *not(args)
  struct node *args;
{
    struct node *rval;
    int val;

    /* evaluate the argument */
    val = xlevmatch(INT,&args)->n_int;

    /* make sure there aren't any more arguments */
    xllastarg(args);

    /* convert and check the value  */
    rval = newnode(INT);
    rval->n_int = ~val;

    /* return the result value */
    return (rval);
}

/* abs - absolute value */
static struct node *abs(args)
  struct node *args;
{
    struct node *rval;
    int val;

    /* evaluate the argument */
    val = xlevmatch(INT,&args)->n_int;

    /* make sure there aren't any more arguments */
    xllastarg(args);

    /* convert and check the value  */
    rval = newnode(INT);
    rval->n_int = val >= 0 ? val : -val ;

    /* return the result value */
    return (rval);
}

/* min - builtin function for minimum */
static int xmin(val,arg)
  int val,arg;
{
    return (val < arg ? val : arg);
}
static struct node *min(args)
  struct node *args;
{
    return (arith(args,xmin));
}

/* max - builtin function for maximum */
static int xmax(val,arg)
  int val,arg;
{
    return (val > arg ? val : arg);
}
static struct node *max(args)
  struct node *args;
{
    return (arith(args,xmax));
}

/* arith - common arithmetic function */
static struct node *arith(args,funct)
  struct node *args; int (*funct)();
{
    struct node *oldstk,arg,*val;
    int first,ival,iarg;

    /* create a new stack frame */
    oldstk = xlsave(&arg,NULL);

    /* initialize */
    arg.n_ptr = args;
    first = TRUE;
    ival = 0;

    /* evaluate and sum each argument */
    while (arg.n_ptr != NULL) {

	/* get the next argument */
	iarg = xlevmatch(INT,&arg.n_ptr)->n_int;

	/* accumulate the result value */
	if (first) {
	    ival = iarg;
	    first = FALSE;
	}
	else
	    ival = (*funct)(ival,iarg);
    }

    /* initialize value */
    val = newnode(INT);
    val->n_int = ival;

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the result value */
    return (val);
}

/* land - logical and */
static struct node *land(args)
  struct node *args;
{
    struct node *oldstk,arg,*val;

    /* create a new stack frame */
    oldstk = xlsave(&arg,NULL);

    /* initialize */
    arg.n_ptr = args;
    val = true;

    /* evaluate each argument */
    while (arg.n_ptr != NULL)

	/* get the next argument */
	if (xlevarg(&arg.n_ptr) == NULL) {
	    val = NULL;
	    break;
	}

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the result value */
    return (val);
}

/* lor - logical or */
static struct node *lor(args)
  struct node *args;
{
    struct node *oldstk,arg,*val;

    /* create a new stack frame */
    oldstk = xlsave(&arg,NULL);

    /* initialize */
    arg.n_ptr = args;
    val = NULL;

    /* evaluate each argument */
    while (arg.n_ptr != NULL)
	if (xlevarg(&arg.n_ptr) != NULL) {
	    val = true;
	    break;
	}

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return the result value */
    return (val);
}

/* lnot - logical not */
static struct node *lnot(args)
  struct node *args;
{
    struct node *val;

    /* evaluate the argument */
    val = xlevarg(&args);

    /* make sure there aren't any more arguments */
    xllastarg(args);

    /* convert and check the value  */
    if (val == NULL)
	return (true);
    else
	return (NULL);
}

/* lss - builtin function for < */
static int xlss(cmp)
  int cmp;
{
    return (cmp < 0);
}
static struct node *lss(args)
  struct node *args;
{
    return (compare(args,xlss));
}

/* leq - builtin function for <= */
static int xleq(cmp)
  int cmp;
{
    return (cmp <= 0);
}
static struct node *leq(args)
  struct node *args;
{
    return (compare(args,xleq));
}

/* eql - builtin function for == */
static int xeql(cmp)
  int cmp;
{
    return (cmp == 0);
}
static struct node *eql(args)
  struct node *args;
{
    return (compare(args,xeql));
}

/* neq - builtin function for != */
static int xneq(cmp)
  int cmp;
{
    return (cmp != 0);
}
static struct node *neq(args)
  struct node *args;
{
    return (compare(args,xneq));
}

/* geq - builtin function for >= */
static int xgeq(cmp)
  int cmp;
{
    return (cmp >= 0);
}
static struct node *geq(args)
  struct node *args;
{
    return (compare(args,xgeq));
}

/* gtr - builtin function for > */
static int xgtr(cmp)
  int cmp;
{
    return (cmp > 0);
}
static struct node *gtr(args)
  struct node *args;
{
    return (compare(args,xgtr));
}

/* compare - common compare function */
static struct node *compare(args,funct)
  struct node *args; int (*funct)();
{
    struct node *oldstk,arg,arg1,arg2;
    int type1,type2,cmp;

    /* create a new stack frame */
    oldstk = xlsave(&arg,&arg1,&arg2,NULL);

    /* initialize */
    arg.n_ptr = args;

    /* get argument 1 */
    arg1.n_ptr = xlevarg(&arg.n_ptr);
    type1 = gettype(arg1.n_ptr);

    /* get argument 2 */
    arg2.n_ptr = xlevarg(&arg.n_ptr);
    type2 = gettype(arg2.n_ptr);

    /* make sure there aren't any more arguments */
    xllastarg(arg.n_ptr);

    /* do the compare */
    if (type1 == STR && type2 == STR)
	cmp = strcmp(arg1.n_ptr->n_str,arg2.n_ptr->n_str);
    else if (type1 == INT && type2 == INT)
	cmp = arg1.n_ptr->n_int - arg2.n_ptr->n_int;
    else
	cmp = arg1.n_ptr - arg2.n_ptr;

    /* restore the previous stack frame */
    xlstack = oldstk;

    /* return result of the compare */
    if ((*funct)(cmp))
	return (true);
    else
	return (NULL);
}

/* gettype - return the type of an argument */
static int gettype(arg)
  struct node *arg;
{
    if (arg == NULL)
	return (LIST);
    else
	return (arg->n_type);
}

/* xlminit - xlisp math initialization routine */
xlminit()
{
    xlsubr("+",add);
    xlsubr("-",sub);
    xlsubr("*",mul);
    xlsubr("/",div);
    xlsubr("%",mod);
    xlsubr("&",and);
    xlsubr("|",or);
    xlsubr("~",not);
    xlsubr("<",lss);
    xlsubr("<=",leq);
    xlsubr("==",eql);
    xlsubr("!=",neq);
    xlsubr(">=",geq);
    xlsubr(">",gtr);
    xlsubr("&&",land);
    xlsubr("||",lor);
    xlsubr("!",lnot);
    xlsubr("min",min);
    xlsubr("max",max);
    xlsubr("abs",abs);
    true = xlenter("t");
    true->n_symvalue = true;
}