[comp.sources.misc] v10i091: XLisP 2.1 sources 2/5

garym@cognos.UUCP (Gary Murphy) (02/27/90)

Posting-number: Volume 10, Issue 91
Submitted-by: garym@cognos.UUCP (Gary Murphy)
Archive-name: xlisp21/part04

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	xlbfun.c
#	xlcont.c
#	xldbug.c
#	xldmem.c
#	xldmem.h
#	xleval.c
# This archive created: Sun Feb 18 07:45:24 1990
# By:	Gary Murphy ()
export PATH; PATH=/bin:$PATH
echo shar: extracting "'xlbfun.c'" '(12891 characters)'
if test -f 'xlbfun.c'
then
	echo shar: over-writing existing file "'xlbfun.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'xlbfun.c'
X/* xlbfun.c - xlisp basic built-in functions */
X/*	Copyright (c) 1985, by David Michael Betz
X	All Rights Reserved
X	Permission is granted for unrestricted non-commercial use	*/
X
X#include "xlisp.h"
X
X/* external variables */
Xextern LVAL xlenv,xlfenv,xldenv,true;
Xextern LVAL s_evalhook,s_applyhook;
Xextern LVAL s_car,s_cdr,s_nth,s_get,s_svalue,s_splist,s_aref;
Xextern LVAL s_lambda,s_macro;
Xextern LVAL s_comma,s_comat;
Xextern LVAL s_unbound;
Xextern char gsprefix[];
Xextern int gsnumber;
X
X/* external routines */
Xextern LVAL xlxeval();
X
X/* forward declarations */
XFORWARD LVAL bquote1();
XFORWARD LVAL defun();
XFORWARD LVAL makesymbol();
X
X/* xeval - the built-in function 'eval' */
XLVAL xeval()
X{
X    LVAL expr;
X
X    /* get the expression to evaluate */
X    expr = xlgetarg();
X    xllastarg();
X
X    /* evaluate the expression */
X    return (xleval(expr));
X}
X
X/* xapply - the built-in function 'apply' */
XLVAL xapply()
X{
X    LVAL fun,arglist;
X
X    /* get the function and argument list */
X    fun = xlgetarg();
X    arglist = xlgalist();
X    xllastarg();
X
X    /* apply the function to the arguments */
X    return (xlapply(pushargs(fun,arglist)));
X}
X
X/* xfuncall - the built-in function 'funcall' */
XLVAL xfuncall()
X{
X    LVAL *newfp;
X    int argc;
X    
X    /* build a new argument stack frame */
X    newfp = xlsp;
X    pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
X    pusharg(xlgetarg());
X    pusharg(NIL); /* will be argc */
X
X    /* push each argument */
X    for (argc = 0; moreargs(); ++argc)
X	pusharg(nextarg());
X
X    /* establish the new stack frame */
X    newfp[2] = cvfixnum((FIXTYPE)argc);
X    xlfp = newfp;
X
X    /* apply the function to the arguments */
X    return (xlapply(argc));
X}
X
X/* xmacroexpand - expand a macro call repeatedly */
XLVAL xmacroexpand()
X{
X    LVAL form;
X    form = xlgetarg();
X    xllastarg();
X    return (xlexpandmacros(form));
X}
X
X/* x1macroexpand - expand a macro call */
XLVAL x1macroexpand()
X{
X    LVAL form,fun,args;
X
X    /* protect some pointers */
X    xlstkcheck(2);
X    xlsave(fun);
X    xlsave(args);
X
X    /* get the form */
X    form = xlgetarg();
X    xllastarg();
X
X    /* expand until the form isn't a macro call */
X    if (consp(form)) {
X	fun = car(form);		/* get the macro name */
X	args = cdr(form);		/* get the arguments */
X	if (symbolp(fun) && fboundp(fun)) {
X	    fun = xlgetfunction(fun);	/* get the expansion function */
X	    macroexpand(fun,args,&form);
X	}
X    }
X
X    /* restore the stack and return the expansion */
X    xlpopn(2);
X    return (form);
X}
X
X/* xatom - is this an atom? */
XLVAL xatom()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (atom(arg) ? true : NIL);
X}
X
X/* xsymbolp - is this an symbol? */
XLVAL xsymbolp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (arg == NIL || symbolp(arg) ? true : NIL);
X}
X
X/* xnumberp - is this a number? */
XLVAL xnumberp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (fixp(arg) || floatp(arg) ? true : NIL);
X}
X
X/* xintegerp - is this an integer? */
XLVAL xintegerp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (fixp(arg) ? true : NIL);
X}
X
X/* xfloatp - is this a float? */
XLVAL xfloatp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (floatp(arg) ? true : NIL);
X}
X
X/* xcharp - is this a character? */
XLVAL xcharp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (charp(arg) ? true : NIL);
X}
X
X/* xstringp - is this a string? */
XLVAL xstringp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (stringp(arg) ? true : NIL);
X}
X
X/* xarrayp - is this an array? */
XLVAL xarrayp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (vectorp(arg) ? true : NIL);
X}
X
X/* xstreamp - is this a stream? */
XLVAL xstreamp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (streamp(arg) || ustreamp(arg) ? true : NIL);
X}
X
X/* xobjectp - is this an object? */
XLVAL xobjectp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (objectp(arg) ? true : NIL);
X}
X
X/* xboundp - is this a value bound to this symbol? */
XLVAL xboundp()
X{
X    LVAL sym;
X    sym = xlgasymbol();
X    xllastarg();
X    return (boundp(sym) ? true : NIL);
X}
X
X/* xfboundp - is this a functional value bound to this symbol? */
XLVAL xfboundp()
X{
X    LVAL sym;
X    sym = xlgasymbol();
X    xllastarg();
X    return (fboundp(sym) ? true : NIL);
X}
X
X/* xnull - is this null? */
XLVAL xnull()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (null(arg) ? true : NIL);
X}
X
X/* xlistp - is this a list? */
XLVAL xlistp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (listp(arg) ? true : NIL);
X}
X
X/* xendp - is this the end of a list? */
XLVAL xendp()
X{
X    LVAL arg;
X    arg = xlgalist();
X    xllastarg();
X    return (null(arg) ? true : NIL);
X}
X
X/* xconsp - is this a cons? */
XLVAL xconsp()
X{
X    LVAL arg;
X    arg = xlgetarg();
X    xllastarg();
X    return (consp(arg) ? true : NIL);
X}
X
X/* xeq - are these equal? */
XLVAL xeq()
X{
X    LVAL arg1,arg2;
X
X    /* get the two arguments */
X    arg1 = xlgetarg();
X    arg2 = xlgetarg();
X    xllastarg();
X
X    /* compare the arguments */
X    return (arg1 == arg2 ? true : NIL);
X}
X
X/* xeql - are these equal? */
XLVAL xeql()
X{
X    LVAL arg1,arg2;
X
X    /* get the two arguments */
X    arg1 = xlgetarg();
X    arg2 = xlgetarg();
X    xllastarg();
X
X    /* compare the arguments */
X    return (eql(arg1,arg2) ? true : NIL);
X}
X
X/* xequal - are these equal? (recursive) */
XLVAL xequal()
X{
X    LVAL arg1,arg2;
X
X    /* get the two arguments */
X    arg1 = xlgetarg();
X    arg2 = xlgetarg();
X    xllastarg();
X
X    /* compare the arguments */
X    return (equal(arg1,arg2) ? true : NIL);
X}
X
X/* xset - built-in function set */
XLVAL xset()
X{
X    LVAL sym,val;
X
X    /* get the symbol and new value */
X    sym = xlgasymbol();
X    val = xlgetarg();
X    xllastarg();
X
X    /* assign the symbol the value of argument 2 and the return value */
X    setvalue(sym,val);
X
X    /* return the result value */
X    return (val);
X}
X
X/* xgensym - generate a symbol */
XLVAL xgensym()
X{
X    char sym[STRMAX+11]; /* enough space for prefix and number */
X    LVAL x;
X
X    /* get the prefix or number */
X    if (moreargs()) {
X	x = xlgetarg();
X	switch (ntype(x)) {
X	case SYMBOL:
X		x = getpname(x);
X	case STRING:
X		strncpy(gsprefix,getstring(x),STRMAX);
X		gsprefix[STRMAX] = '\0';
X		break;
X	case FIXNUM:
X		gsnumber = getfixnum(x);
X		break;
X	default:
X		xlerror("bad argument type",x);
X	}
X    }
X    xllastarg();
X
X    /* create the pname of the new symbol */
X    sprintf(sym,"%s%d",gsprefix,gsnumber++);
X
X    /* make a symbol with this print name */
X    return (xlmakesym(sym));
X}
X
X/* xmakesymbol - make a new uninterned symbol */
XLVAL xmakesymbol()
X{
X    return (makesymbol(FALSE));
X}
X
X/* xintern - make a new interned symbol */
XLVAL xintern()
X{
X    return (makesymbol(TRUE));
X}
X
X/* makesymbol - make a new symbol */
XLOCAL LVAL makesymbol(iflag)
X  int iflag;
X{
X    LVAL pname;
X
X    /* get the print name of the symbol to intern */
X    pname = xlgastring();
X    xllastarg();
X
X    /* make the symbol */
X    return (iflag ? xlenter(getstring(pname))
X    		  : xlmakesym(getstring(pname)));
X}
X
X/* xsymname - get the print name of a symbol */
XLVAL xsymname()
X{
X    LVAL sym;
X
X    /* get the symbol */
X    sym = xlgasymbol();
X    xllastarg();
X
X    /* return the print name */
X    return (getpname(sym));
X}
X
X/* xsymvalue - get the value of a symbol */
XLVAL xsymvalue()
X{
X    LVAL sym,val;
X
X    /* get the symbol */
X    sym = xlgasymbol();
X    xllastarg();
X
X    /* get the global value */
X    while ((val = getvalue(sym)) == s_unbound)
X	xlunbound(sym);
X
X    /* return its value */
X    return (val);
X}
X
X/* xsymfunction - get the functional value of a symbol */
XLVAL xsymfunction()
X{
X    LVAL sym,val;
X
X    /* get the symbol */
X    sym = xlgasymbol();
X    xllastarg();
X
X    /* get the global value */
X    while ((val = getfunction(sym)) == s_unbound)
X	xlfunbound(sym);
X
X    /* return its value */
X    return (val);
X}
X
X/* xsymplist - get the property list of a symbol */
XLVAL xsymplist()
X{
X    LVAL sym;
X
X    /* get the symbol */
X    sym = xlgasymbol();
X    xllastarg();
X
X    /* return the property list */
X    return (getplist(sym));
X}
X
X/* xget - get the value of a property */
XLVAL xget()
X{
X    LVAL sym,prp;
X
X    /* get the symbol and property */
X    sym = xlgasymbol();
X    prp = xlgasymbol();
X    xllastarg();
X
X    /* retrieve the property value */
X    return (xlgetprop(sym,prp));
X}
X
X/* xputprop - set the value of a property */
XLVAL xputprop()
X{
X    LVAL sym,val,prp;
X
X    /* get the symbol and property */
X    sym = xlgasymbol();
X    val = xlgetarg();
X    prp = xlgasymbol();
X    xllastarg();
X
X    /* set the property value */
X    xlputprop(sym,val,prp);
X
X    /* return the value */
X    return (val);
X}
X
X/* xremprop - remove a property value from a property list */
XLVAL xremprop()
X{
X    LVAL sym,prp;
X
X    /* get the symbol and property */
X    sym = xlgasymbol();
X    prp = xlgasymbol();
X    xllastarg();
X
X    /* remove the property */
X    xlremprop(sym,prp);
X
X    /* return nil */
X    return (NIL);
X}
X
X/* xhash - compute the hash value of a string or symbol */
XLVAL xhash()
X{
X    unsigned char *str;
X    LVAL len,val;
X    int n;
X
X    /* get the string and the table length */
X    val = xlgetarg();
X    len = xlgafixnum(); n = (int)getfixnum(len);
X    xllastarg();
X
X    /* get the string */
X    if (symbolp(val))
X	str = getstring(getpname(val));
X    else if (stringp(val))
X	str = getstring(val);
X    else
X	xlerror("bad argument type",val);
X
X    /* return the hash index */
X    return (cvfixnum((FIXTYPE)hash(str,n)));
X}
X
X/* xaref - array reference function */
XLVAL xaref()
X{
X    LVAL array,index;
X    int i;
X
X    /* get the array and the index */
X    array = xlgavector();
X    index = xlgafixnum(); i = (int)getfixnum(index);
X    xllastarg();
X
X    /* range check the index */
X    if (i < 0 || i >= getsize(array))
X	xlerror("array index out of bounds",index);
X
X    /* return the array element */
X    return (getelement(array,i));
X}
X
X/* xmkarray - make a new array */
XLVAL xmkarray()
X{
X    LVAL size;
X    int n;
X
X    /* get the size of the array */
X    size = xlgafixnum() ; n = (int)getfixnum(size);
X    xllastarg();
X
X    /* create the array */
X    return (newvector(n));
X}
X
X/* xvector - make a vector */
XLVAL xvector()
X{
X    LVAL val;
X    int i;
X
X    /* make the vector */
X    val = newvector(xlargc);
X
X    /* store each argument */
X    for (i = 0; moreargs(); ++i)
X	setelement(val,i,nextarg());
X    xllastarg();
X
X    /* return the vector */
X    return (val);
X}
X
X/* xerror - special form 'error' */
XLVAL xerror()
X{
X    LVAL emsg,arg;
X
X    /* get the error message and the argument */
X    emsg = xlgastring();
X    arg = (moreargs() ? xlgetarg() : s_unbound);
X    xllastarg();
X
X    /* signal the error */
X    xlerror(getstring(emsg),arg);
X}
X
X/* xcerror - special form 'cerror' */
XLVAL xcerror()
X{
X    LVAL cmsg,emsg,arg;
X
X    /* get the correction message, the error message, and the argument */
X    cmsg = xlgastring();
X    emsg = xlgastring();
X    arg = (moreargs() ? xlgetarg() : s_unbound);
X    xllastarg();
X
X    /* signal the error */
X    xlcerror(getstring(cmsg),getstring(emsg),arg);
X
X    /* return nil */
X    return (NIL);
X}
X
X/* xbreak - special form 'break' */
XLVAL xbreak()
X{
X    LVAL emsg,arg;
X
X    /* get the error message */
X    emsg = (moreargs() ? xlgastring() : NIL);
X    arg = (moreargs() ? xlgetarg() : s_unbound);
X    xllastarg();
X
X    /* enter the break loop */
X    xlbreak((emsg ? getstring(emsg) : (unsigned char *)"**BREAK**"),arg);
X
X    /* return nil */
X    return (NIL);
X}
X
X/* xcleanup - special form 'clean-up' */
XLVAL xcleanup()
X{
X    xllastarg();
X    xlcleanup();
X}
X
X/* xtoplevel - special form 'top-level' */
XLVAL xtoplevel()
X{
X    xllastarg();
X    xltoplevel();
X}
X
X/* xcontinue - special form 'continue' */
XLVAL xcontinue()
X{
X    xllastarg();
X    xlcontinue();
X}
X
X/* xevalhook - eval hook function */
XLVAL xevalhook()
X{
X    LVAL expr,newehook,newahook,newenv,oldenv,oldfenv,olddenv,val;
X
X    /* protect some pointers */
X    xlstkcheck(3);
X    xlsave(oldenv);
X    xlsave(oldfenv);
X    xlsave(newenv);
X
X    /* get the expression, the new hook functions and the environment */
X    expr = xlgetarg();
X    newehook = xlgetarg();
X    newahook = xlgetarg();
X    newenv = (moreargs() ? xlgalist() : NIL);
X    xllastarg();
X
X    /* bind *evalhook* and *applyhook* to the hook functions */
X    olddenv = xldenv;
X    xldbind(s_evalhook,newehook);
X    xldbind(s_applyhook,newahook);
X
X    /* establish the environment for the hook function */
X    if (newenv) {
X	oldenv = xlenv;
X	oldfenv = xlfenv;
X	xlenv = car(newenv);
X	xlfenv = cdr(newenv);
X    }
X
X    /* evaluate the expression (bypassing *evalhook*) */
X    val = xlxeval(expr);
X
X    /* restore the old environment */
X    xlunbind(olddenv);
X    if (newenv) {
X	xlenv = oldenv;
X	xlfenv = oldfenv;
X    }
X
X    /* restore the stack */
X    xlpopn(3);
X
X    /* return the result */
X    return (val);
X}
X
SHAR_EOF
if test 12891 -ne "`wc -c 'xlbfun.c'`"
then
	echo shar: error transmitting "'xlbfun.c'" '(should have been 12891 characters)'
fi
echo shar: extracting "'xlcont.c'" '(28157 characters)'
if test -f 'xlcont.c'
then
	echo shar: over-writing existing file "'xlcont.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'xlcont.c'
X/* xlcont - xlisp special forms */
X/*	Copyright (c) 1985, by David Michael Betz
X	All Rights Reserved
X	Permission is granted for unrestricted non-commercial use	*/
X
X#include "xlisp.h"
X
X/* external variables */
Xextern LVAL xlenv,xlfenv,xldenv,xlvalue;
Xextern LVAL s_setf,s_car,s_cdr,s_nth,s_aref,s_get;
Xextern LVAL s_svalue,s_sfunction,s_splist;
Xextern LVAL s_lambda,s_macro;
Xextern LVAL s_comma,s_comat;
Xextern LVAL s_unbound;
Xextern LVAL true;
X
X/* external routines */
Xextern LVAL makearglist();
X
X/* forward declarations */
XFORWARD LVAL bquote1();
XFORWARD LVAL let();
XFORWARD LVAL flet();
XFORWARD LVAL prog();
XFORWARD LVAL progx();
XFORWARD LVAL doloop();
XFORWARD LVAL evarg();
XFORWARD LVAL match();
XFORWARD LVAL evmatch();
X
X/* dummy node type for a list */
X#define LIST	-1
X
X/* xquote - special form 'quote' */
XLVAL xquote()
X{
X    LVAL val;
X    val = xlgetarg();
X    xllastarg();
X    return (val);
X}
X
X/* xfunction - special form 'function' */
XLVAL xfunction()
X{
X    LVAL val;
X
X    /* get the argument */
X    val = xlgetarg();
X    xllastarg();
X
X    /* create a closure for lambda expressions */
X    if (consp(val) && car(val) == s_lambda && consp(cdr(val)))
X	val = xlclose(NIL,s_lambda,car(cdr(val)),cdr(cdr(val)),xlenv,xlfenv);
X
X    /* otherwise, get the value of a symbol */
X    else if (symbolp(val))
X	val = xlgetfunction(val);
X
X    /* otherwise, its an error */
X    else
X	xlerror("not a function",val);
X
X    /* return the function */
X    return (val);
X}
X
X/* xbquote - back quote special form */
XLVAL xbquote()
X{
X    LVAL expr;
X
X    /* get the expression */
X    expr = xlgetarg();
X    xllastarg();
X
X    /* fill in the template */
X    return (bquote1(expr));
X}
X
X/* bquote1 - back quote helper function */
XLOCAL LVAL bquote1(expr)
X  LVAL expr;
X{
X    LVAL val,list,last,new;
X
X    /* handle atoms */
X    if (atom(expr))
X	val = expr;
X
X    /* handle (comma <expr>) */
X    else if (car(expr) == s_comma) {
X	if (atom(cdr(expr)))
X	    xlfail("bad comma expression");
X	val = xleval(car(cdr(expr)));
X    }
X
X    /* handle ((comma-at <expr>) ... ) */
X    else if (consp(car(expr)) && car(car(expr)) == s_comat) {
X	xlstkcheck(2);
X	xlsave(list);
X	xlsave(val);
X	if (atom(cdr(car(expr))))
X	    xlfail("bad comma-at expression");
X	list = xleval(car(cdr(car(expr))));
X	for (last = NIL; consp(list); list = cdr(list)) {
X	    new = consa(car(list));
X	    if (last)
X		rplacd(last,new);
X	    else
X		val = new;
X	    last = new;
X	}
X	if (last)
X	    rplacd(last,bquote1(cdr(expr)));
X	else
X	    val = bquote1(cdr(expr));
X	xlpopn(2);
X    }
X
X    /* handle any other list */
X    else {
X	xlsave1(val);
X	val = consa(NIL);
X	rplaca(val,bquote1(car(expr)));
X	rplacd(val,bquote1(cdr(expr)));
X	xlpop();
X    }
X
X    /* return the result */
X    return (val);
X}
X
X/* xlambda - special form 'lambda' */
XLVAL xlambda()
X{
X    LVAL fargs,arglist,val;
X
X    /* get the formal argument list and function body */
X    xlsave1(arglist);
X    fargs = xlgalist();
X    arglist = makearglist(xlargc,xlargv);
X
X    /* create a new function definition */
X    val = xlclose(NIL,s_lambda,fargs,arglist,xlenv,xlfenv);
X
X    /* restore the stack and return the closure */
X    xlpop();
X    return (val);
X}
X
X/* xgetlambda - get the lambda expression associated with a closure */
XLVAL xgetlambda()
X{
X    LVAL closure;
X    closure = xlgaclosure();
X    return (cons(gettype(closure),
X                 cons(getlambda(closure),getbody(closure))));
X}
X
X/* xsetq - special form 'setq' */
XLVAL xsetq()
X{
X    LVAL sym,val;
X
X    /* handle each pair of arguments */
X    for (val = NIL; moreargs(); ) {
X	sym = xlgasymbol();
X	val = xleval(nextarg());
X	xlsetvalue(sym,val);
X    }
X
X    /* return the result value */
X    return (val);
X}
X
X/* xpsetq - special form 'psetq' */
XLVAL xpsetq()
X{
X    LVAL plist,sym,val;
X
X    /* protect some pointers */
X    xlsave1(plist);
X
X    /* handle each pair of arguments */
X    for (val = NIL; moreargs(); ) {
X	sym = xlgasymbol();
X	val = xleval(nextarg());
X	plist = cons(cons(sym,val),plist);
X    }
X
X    /* do parallel sets */
X    for (; plist; plist = cdr(plist))
X	xlsetvalue(car(car(plist)),cdr(car(plist)));
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the result value */
X    return (val);
X}
X
X/* xsetf - special form 'setf' */
XLVAL xsetf()
X{
X    LVAL place,value;
X
X    /* protect some pointers */
X    xlsave1(value);
X
X    /* handle each pair of arguments */
X    while (moreargs()) {
X
X	/* get place and value */
X	place = xlgetarg();
X	value = xleval(nextarg());
X
X	/* expand macros in the place form */
X	if (consp(place))
X	    place = xlexpandmacros(place);
X	
X	/* check the place form */
X	if (symbolp(place))
X	    xlsetvalue(place,value);
X	else if (consp(place))
X	    placeform(place,value);
X	else
X	    xlfail("bad place form");
X    }
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the value */
X    return (value);
X}
X
X/* placeform - handle a place form other than a symbol */
XLOCAL placeform(place,value)
X  LVAL place,value;
X{
X    LVAL fun,arg1,arg2;
X    int i;
X
X    /* check the function name */
X    if ((fun = match(SYMBOL,&place)) == s_get) {
X	xlstkcheck(2);
X	xlsave(arg1);
X	xlsave(arg2);
X	arg1 = evmatch(SYMBOL,&place);
X	arg2 = evmatch(SYMBOL,&place);
X	if (place) toomany(place);
X	xlputprop(arg1,value,arg2);
X	xlpopn(2);
X    }
X    else if (fun == s_svalue) {
X	arg1 = evmatch(SYMBOL,&place);
X	if (place) toomany(place);
X	setvalue(arg1,value);
X    }
X    else if (fun == s_sfunction) {
X	arg1 = evmatch(SYMBOL,&place);
X	if (place) toomany(place);
X	setfunction(arg1,value);
X    }
X    else if (fun == s_splist) {
X	arg1 = evmatch(SYMBOL,&place);
X	if (place) toomany(place);
X	setplist(arg1,value);
X    }
X    else if (fun == s_car) {
X	arg1 = evmatch(CONS,&place);
X	if (place) toomany(place);
X	rplaca(arg1,value);
X    }
X    else if (fun == s_cdr) {
X	arg1 = evmatch(CONS,&place);
X	if (place) toomany(place);
X	rplacd(arg1,value);
X    }
X    else if (fun == s_nth) {
X	xlsave1(arg1);
X	arg1 = evmatch(FIXNUM,&place);
X	arg2 = evmatch(LIST,&place);
X	if (place) toomany(place);
X	for (i = (int)getfixnum(arg1); i > 0 && consp(arg2); --i)
X	    arg2 = cdr(arg2);
X	if (consp(arg2))
X	    rplaca(arg2,value);
X	xlpop();
X    }
X    else if (fun == s_aref) {
X	xlsave1(arg1);
X	arg1 = evmatch(VECTOR,&place);
X	arg2 = evmatch(FIXNUM,&place); i = (int)getfixnum(arg2);
X	if (place) toomany(place);
X	if (i < 0 || i >= getsize(arg1))
X	    xlerror("index out of range",arg2);
X	setelement(arg1,i,value);
X	xlpop();
X    }
X    else if (fun = xlgetprop(fun,s_setf))
X	setffunction(fun,place,value);
X    else
X	xlfail("bad place form");
X}
X
X/* setffunction - call a user defined setf function */
XLOCAL setffunction(fun,place,value)
X  LVAL fun,place,value;
X{
X    LVAL *newfp;
X    int argc;
X
X    /* create the new call frame */
X    newfp = xlsp;
X    pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
X    pusharg(fun);
X    pusharg(NIL);
X
X    /* push the values of all of the place expressions and the new value */
X    for (argc = 1; consp(place); place = cdr(place), ++argc)
X	pusharg(xleval(car(place)));
X    pusharg(value);
X
X    /* insert the argument count and establish the call frame */
X    newfp[2] = cvfixnum((FIXTYPE)argc);
X    xlfp = newfp;
X
X    /* apply the function */
X    xlapply(argc);
X}
X		       
X/* xdefun - special form 'defun' */
XLVAL xdefun()
X{
X    LVAL sym,fargs,arglist;
X
X    /* get the function symbol and formal argument list */
X    xlsave1(arglist);
X    sym = xlgasymbol();
X    fargs = xlgalist();
X    arglist = makearglist(xlargc,xlargv);
X
X    /* make the symbol point to a new function definition */
X    xlsetfunction(sym,xlclose(sym,s_lambda,fargs,arglist,xlenv,xlfenv));
X
X    /* restore the stack and return the function symbol */
X    xlpop();
X    return (sym);
X}
X
X/* xdefmacro - special form 'defmacro' */
XLVAL xdefmacro()
X{
X    LVAL sym,fargs,arglist;
X
X    /* get the function symbol and formal argument list */
X    xlsave1(arglist);
X    sym = xlgasymbol();
X    fargs = xlgalist();
X    arglist = makearglist(xlargc,xlargv);
X
X    /* make the symbol point to a new function definition */
X    xlsetfunction(sym,xlclose(sym,s_macro,fargs,arglist,NIL,NIL));
X
X    /* restore the stack and return the function symbol */
X    xlpop();
X    return (sym);
X}
X
X/* xcond - special form 'cond' */
XLVAL xcond()
X{
X    LVAL list,val;
X
X    /* find a predicate that is true */
X    for (val = NIL; moreargs(); ) {
X
X	/* get the next conditional */
X	list = nextarg();
X
X	/* evaluate the predicate part */
X	if (consp(list) && (val = xleval(car(list)))) {
X
X	    /* evaluate each expression */
X	    for (list = cdr(list); consp(list); list = cdr(list))
X		val = xleval(car(list));
X
X	    /* exit the loop */
X	    break;
X	}
X    }
X
X    /* return the value */
X    return (val);
X}
X
X/* xwhen - special form 'when' */
XLVAL xwhen()
X{
X    LVAL val;
X
X    /* check the test expression */
X    if (val = xleval(xlgetarg()))
X	while (moreargs())
X	    val = xleval(nextarg());
X
X    /* return the value */
X    return (val);
X}
X
X/* xunless - special form 'unless' */
XLVAL xunless()
X{
X    LVAL val=NIL;
X
X    /* check the test expression */
X    if (xleval(xlgetarg()) == NIL)
X	while (moreargs())
X	    val = xleval(nextarg());
X
X    /* return the value */
X    return (val);
X}
X
X/* xcase - special form 'case' */
XLVAL xcase()
X{
X    LVAL key,list,cases,val;
X
X    /* protect some pointers */
X    xlsave1(key);
X
X    /* get the key expression */
X    key = xleval(nextarg());
X
X    /* find a case that matches */
X    for (val = NIL; moreargs(); ) {
X
X	/* get the next case clause */
X	list = nextarg();
X
X	/* make sure this is a valid clause */
X	if (consp(list)) {
X
X	    /* compare the key list against the key */
X	    if ((cases = car(list)) == true ||
X                (listp(cases) && keypresent(key,cases)) ||
X                eql(key,cases)) {
X
X		/* evaluate each expression */
X		for (list = cdr(list); consp(list); list = cdr(list))
X		    val = xleval(car(list));
X
X		/* exit the loop */
X		break;
X	    }
X	}
X	else
X	    xlerror("bad case clause",list);
X    }
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the value */
X    return (val);
X}
X
X/* keypresent - check for the presence of a key in a list */
XLOCAL int keypresent(key,list)
X  LVAL key,list;
X{
X    for (; consp(list); list = cdr(list))
X	if (eql(car(list),key))
X	    return (TRUE);
X    return (FALSE);
X}
X
X/* xand - special form 'and' */
XLVAL xand()
X{
X    LVAL val;
X
X    /* evaluate each argument */
X    for (val = true; moreargs(); )
X	if ((val = xleval(nextarg())) == NIL)
X	    break;
X
X    /* return the result value */
X    return (val);
X}
X
X/* xor - special form 'or' */
XLVAL xor()
X{
X    LVAL val;
X
X    /* evaluate each argument */
X    for (val = NIL; moreargs(); )
X	if ((val = xleval(nextarg())))
X	    break;
X
X    /* return the result value */
X    return (val);
X}
X
X/* xif - special form 'if' */
XLVAL xif()
X{
X    LVAL testexpr,thenexpr,elseexpr;
X
X    /* get the test expression, then clause and else clause */
X    testexpr = xlgetarg();
X    thenexpr = xlgetarg();
X    elseexpr = (moreargs() ? xlgetarg() : NIL);
X    xllastarg();
X
X    /* evaluate the appropriate clause */
X    return (xleval(xleval(testexpr) ? thenexpr : elseexpr));
X}
X
X/* xlet - special form 'let' */
XLVAL xlet()
X{
X    return (let(TRUE));
X}
X
X/* xletstar - special form 'let*' */
XLVAL xletstar()
X{
X    return (let(FALSE));
X}
X
X/* let - common let routine */
XLOCAL LVAL let(pflag)
X  int pflag;
X{
X    LVAL newenv,val;
X
X    /* protect some pointers */
X    xlsave1(newenv);
X
X    /* create a new environment frame */
X    newenv = xlframe(xlenv);
X
X    /* get the list of bindings and bind the symbols */
X    if (!pflag) xlenv = newenv;
X    dobindings(xlgalist(),newenv);
X    if (pflag) xlenv = newenv;
X
X    /* execute the code */
X    for (val = NIL; moreargs(); )
X	val = xleval(nextarg());
X
X    /* unbind the arguments */
X    xlenv = cdr(xlenv);
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the result */
X    return (val);
X}
X
X/* xflet - built-in function 'flet' */
XLVAL xflet()
X{
X    return (flet(s_lambda,TRUE));
X}
X
X/* xlabels - built-in function 'labels' */
XLVAL xlabels()
X{
X    return (flet(s_lambda,FALSE));
X}
X
X/* xmacrolet - built-in function 'macrolet' */
XLVAL xmacrolet()
X{
X    return (flet(s_macro,TRUE));
X}
X
X/* flet - common flet/labels/macrolet routine */
XLOCAL LVAL flet(type,letflag)
X  LVAL type; int letflag;
X{
X    LVAL list,bnd,sym,fargs,val;
X
X    /* create a new environment frame */
X    xlfenv = xlframe(xlfenv);
X
X    /* bind each symbol in the list of bindings */
X    for (list = xlgalist(); consp(list); list = cdr(list)) {
X
X	/* get the next binding */
X	bnd = car(list);
X
X	/* get the symbol and the function definition */
X	sym = match(SYMBOL,&bnd);
X	fargs = match(LIST,&bnd);
X	val = xlclose(sym,type,fargs,bnd,xlenv,(letflag?cdr(xlfenv):xlfenv));
X
X	/* bind the value to the symbol */
X	xlfbind(sym,val);
X    }
X
X    /* execute the code */
X    for (val = NIL; moreargs(); )
X	val = xleval(nextarg());
X
X    /* unbind the arguments */
X    xlfenv = cdr(xlfenv);
X
X    /* return the result */
X    return (val);
X}
X
X/* xprog - special form 'prog' */
XLVAL xprog()
X{
X    return (prog(TRUE));
X}
X
X/* xprogstar - special form 'prog*' */
XLVAL xprogstar()
X{
X    return (prog(FALSE));
X}
X
X/* prog - common prog routine */
XLOCAL LVAL prog(pflag)
X  int pflag;
X{
X    LVAL newenv,val;
X    CONTEXT cntxt;
X
X    /* protect some pointers */
X    xlsave1(newenv);
X
X    /* create a new environment frame */
X    newenv = xlframe(xlenv);
X
X    /* establish a new execution context */
X    xlbegin(&cntxt,CF_RETURN,NIL);
X    if (setjmp(cntxt.c_jmpbuf))
X	val = xlvalue;
X    else {
X
X	/* get the list of bindings and bind the symbols */
X	if (!pflag) xlenv = newenv;
X	dobindings(xlgalist(),newenv);
X	if (pflag) xlenv = newenv;
X
X	/* execute the code */
X	tagbody();
X	val = NIL;
X
X	/* unbind the arguments */
X	xlenv = cdr(xlenv);
X    }
X    xlend(&cntxt);
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the result */
X    return (val);
X}
X
X/* xgo - special form 'go' */
XLVAL xgo()
X{
X    LVAL label;
X
X    /* get the target label */
X    label = xlgetarg();
X    xllastarg();
X
X    /* transfer to the label */
X    xlgo(label);
X}
X
X/* xreturn - special form 'return' */
XLVAL xreturn()
X{
X    LVAL val;
X
X    /* get the return value */
X    val = (moreargs() ? xleval(nextarg()) : NIL);
X    xllastarg();
X
X    /* return from the inner most block */
X    xlreturn(NIL,val);
X}
X
X/* xrtnfrom - special form 'return-from' */
XLVAL xrtnfrom()
X{
X    LVAL name,val;
X
X    /* get the return value */
X    name = xlgasymbol();
X    val = (moreargs() ? xleval(nextarg()) : NIL);
X    xllastarg();
X
X    /* return from the inner most block */
X    xlreturn(name,val);
X}
X
X/* xprog1 - special form 'prog1' */
XLVAL xprog1()
X{
X    return (progx(1));
X}
X
X/* xprog2 - special form 'prog2' */
XLVAL xprog2()
X{
X    return (progx(2));
X}
X
X/* progx - common progx code */
XLOCAL LVAL progx(n)
X  int n;
X{
X    LVAL val;
X
X    /* protect some pointers */
X    xlsave1(val);
X
X    /* evaluate the first n expressions */
X    while (moreargs() && --n >= 0)
X	val = xleval(nextarg());
X
X    /* evaluate each remaining argument */
X    while (moreargs())
X	xleval(nextarg());
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the last test expression value */
X    return (val);
X}
X
X/* xprogn - special form 'progn' */
XLVAL xprogn()
X{
X    LVAL val;
X
X    /* evaluate each expression */
X    for (val = NIL; moreargs(); )
X	val = xleval(nextarg());
X
X    /* return the last test expression value */
X    return (val);
X}
X
X/* xprogv - special form 'progv' */
XLVAL xprogv()
X{
X    LVAL olddenv,vars,vals,val;
X
X    /* protect some pointers */
X    xlstkcheck(2);
X    xlsave(vars);
X    xlsave(vals);
X
X    /* get the list of variables and the list of values */
X    vars = xlgalist(); vars = xleval(vars);
X    vals = xlgalist(); vals = xleval(vals);
X
X    /* bind the values to the variables */
X    for (olddenv = xldenv; consp(vars); vars = cdr(vars)) {
X	if (!symbolp(car(vars)))
X	    xlerror("expecting a symbol",car(vars));
X	if (consp(vals)) {
X	    xldbind(car(vars),car(vals));
X	    vals = cdr(vals);
X	}
X	else
X	    xldbind(car(vars),s_unbound);
X    }
X
X    /* evaluate each expression */
X    for (val = NIL; moreargs(); )
X	val = xleval(nextarg());
X
X    /* restore the previous environment and the stack */
X    xlunbind(olddenv);
X    xlpopn(2);
X
X    /* return the last test expression value */
X    return (val);
X}
X
X/* xloop - special form 'loop' */
XLVAL xloop()
X{
X    LVAL *argv,arg,val;
X    CONTEXT cntxt;
X    int argc;
X
X    /* protect some pointers */
X    xlsave1(arg);
X
X    /* establish a new execution context */
X    xlbegin(&cntxt,CF_RETURN,NIL);
X    if (setjmp(cntxt.c_jmpbuf))
X	val = xlvalue;
X    else
X	for (argv = xlargv, argc = xlargc; ; xlargv = argv, xlargc = argc)
X	    while (moreargs()) {
X		arg = nextarg();
X		if (consp(arg))
X		    xleval(arg);
X	    }
X    xlend(&cntxt);
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the result */
X    return (val);
X}
X
X/* xdo - special form 'do' */
XLVAL xdo()
X{
X    return (doloop(TRUE));
X}
X
X/* xdostar - special form 'do*' */
XLVAL xdostar()
X{
X    return (doloop(FALSE));
X}
X
X/* doloop - common do routine */
XLOCAL LVAL doloop(pflag)
X  int pflag;
X{
X    LVAL newenv,*argv,blist,clist,test,val;
X    CONTEXT cntxt;
X    int argc;
X
X    /* protect some pointers */
X    xlsave1(newenv);
X
X    /* get the list of bindings, the exit test and the result forms */
X    blist = xlgalist();
X    clist = xlgalist();
X    test = (consp(clist) ? car(clist) : NIL);
X    argv = xlargv;
X    argc = xlargc;
X
X    /* create a new environment frame */
X    newenv = xlframe(xlenv);
X
X    /* establish a new execution context */
X    xlbegin(&cntxt,CF_RETURN,NIL);
X    if (setjmp(cntxt.c_jmpbuf))
X	val = xlvalue;
X    else {
X
X	/* bind the symbols */
X	if (!pflag) xlenv = newenv;
X	dobindings(blist,newenv);
X	if (pflag) xlenv = newenv;
X
X	/* execute the loop as long as the test is false */
X	for (val = NIL; xleval(test) == NIL; doupdates(blist,pflag)) {
X	    xlargv = argv;
X	    xlargc = argc;
X	    tagbody();
X	}
X
X	/* evaluate the result expression */
X	if (consp(clist))
X	    for (clist = cdr(clist); consp(clist); clist = cdr(clist))
X		val = xleval(car(clist));
X
X	/* unbind the arguments */
X	xlenv = cdr(xlenv);
X    }
X    xlend(&cntxt);
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the result */
X    return (val);
X}
X
X/* xdolist - special form 'dolist' */
XLVAL xdolist()
X{
X    LVAL list,*argv,clist,sym,val;
X    CONTEXT cntxt;
X    int argc;
X
X    /* protect some pointers */
X    xlsave1(list);
X
X    /* get the control list (sym list result-expr) */
X    clist = xlgalist();
X    sym = match(SYMBOL,&clist);
X    list = evmatch(LIST,&clist);
X    argv = xlargv;
X    argc = xlargc;
X
X    /* initialize the local environment */
X    xlenv = xlframe(xlenv);
X    xlbind(sym,NIL);
X
X    /* establish a new execution context */
X    xlbegin(&cntxt,CF_RETURN,NIL);
X    if (setjmp(cntxt.c_jmpbuf))
X	val = xlvalue;
X    else {
X
X	/* loop through the list */
X	for (val = NIL; consp(list); list = cdr(list)) {
X
X	    /* bind the symbol to the next list element */
X	    xlsetvalue(sym,car(list));
X
X	    /* execute the loop body */
X	    xlargv = argv;
X	    xlargc = argc;
X	    tagbody();
X	}
X
X	/* evaluate the result expression */
X	xlsetvalue(sym,NIL);
X	val = (consp(clist) ? xleval(car(clist)) : NIL);
X
X	/* unbind the arguments */
X	xlenv = cdr(xlenv);
X    }
X    xlend(&cntxt);
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the result */
X    return (val);
X}
X
X/* xdotimes - special form 'dotimes' */
XLVAL xdotimes()
X{
X    LVAL *argv,clist,sym,cnt,val;
X    CONTEXT cntxt;
X    int argc,n,i;
X
X    /* get the control list (sym list result-expr) */
X    clist = xlgalist();
X    sym = match(SYMBOL,&clist);
X    cnt = evmatch(FIXNUM,&clist); n = getfixnum(cnt);
X    argv = xlargv;
X    argc = xlargc;
X
X    /* initialize the local environment */
X    xlenv = xlframe(xlenv);
X    xlbind(sym,NIL);
X
X    /* establish a new execution context */
X    xlbegin(&cntxt,CF_RETURN,NIL);
X    if (setjmp(cntxt.c_jmpbuf))
X	val = xlvalue;
X    else {
X
X	/* loop through for each value from zero to n-1 */
X	for (val = NIL, i = 0; i < n; ++i) {
X
X	    /* bind the symbol to the next list element */
X	    xlsetvalue(sym,cvfixnum((FIXTYPE)i));
X
X	    /* execute the loop body */
X	    xlargv = argv;
X	    xlargc = argc;
X	    tagbody();
X	}
X
X	/* evaluate the result expression */
X	xlsetvalue(sym,cnt);
X	val = (consp(clist) ? xleval(car(clist)) : NIL);
X
X	/* unbind the arguments */
X	xlenv = cdr(xlenv);
X    }
X    xlend(&cntxt);
X
X    /* return the result */
X    return (val);
X}
X
X/* xblock - special form 'block' */
XLVAL xblock()
X{
X    LVAL name,val;
X    CONTEXT cntxt;
X
X    /* get the block name */
X    name = xlgetarg();
X    if (name && !symbolp(name))
X	xlbadtype(name);
X
X    /* execute the block */
X    xlbegin(&cntxt,CF_RETURN,name);
X    if (setjmp(cntxt.c_jmpbuf))
X	val = xlvalue;
X    else
X	for (val = NIL; moreargs(); )
X	    val = xleval(nextarg());
X    xlend(&cntxt);
X
X    /* return the value of the last expression */
X    return (val);
X}
X
X/* xtagbody - special form 'tagbody' */
XLVAL xtagbody()
X{
X    tagbody();
X    return (NIL);
X}
X
X/* xcatch - special form 'catch' */
XLVAL xcatch()
X{
X    CONTEXT cntxt;
X    LVAL tag,val;
X
X    /* protect some pointers */
X    xlsave1(tag);
X
X    /* get the tag */
X    tag = xleval(nextarg());
X
X    /* establish an execution context */
X    xlbegin(&cntxt,CF_THROW,tag);
X
X    /* check for 'throw' */
X    if (setjmp(cntxt.c_jmpbuf))
X	val = xlvalue;
X
X    /* otherwise, evaluate the remainder of the arguments */
X    else {
X	for (val = NIL; moreargs(); )
X	    val = xleval(nextarg());
X    }
X    xlend(&cntxt);
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the result */
X    return (val);
X}
X
X/* xthrow - special form 'throw' */
XLVAL xthrow()
X{
X    LVAL tag,val;
X
X    /* get the tag and value */
X    tag = xleval(nextarg());
X    val = (moreargs() ? xleval(nextarg()) : NIL);
X    xllastarg();
X
X    /* throw the tag */
X    xlthrow(tag,val);
X}
X
X/* xunwindprotect - special form 'unwind-protect' */
XLVAL xunwindprotect()
X{
X    extern CONTEXT *xltarget;
X    extern int xlmask;
X    CONTEXT cntxt,*target;
X    int mask,sts;
X    LVAL val;
X
X    /* protect some pointers */
X    xlsave1(val);
X
X    /* get the expression to protect */
X    val = xlgetarg();
X
X    /* evaluate the protected expression */
X    xlbegin(&cntxt,CF_UNWIND,NIL);
X    if (sts = setjmp(cntxt.c_jmpbuf)) {
X	target = xltarget;
X	mask = xlmask;
X	val = xlvalue;
X    }
X    else
X	val = xleval(val);
X    xlend(&cntxt);
X	
X    /* evaluate the cleanup expressions */
X    while (moreargs())
X	xleval(nextarg());
X
X    /* if unwinding, continue unwinding */
X    if (sts)
X	xljump(target,mask,val);
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the value of the protected expression */
X    return (val);
X}
X
X/* xerrset - special form 'errset' */
XLVAL xerrset()
X{
X    LVAL expr,flag,val;
X    CONTEXT cntxt;
X
X    /* get the expression and the print flag */
X    expr = xlgetarg();
X    flag = (moreargs() ? xlgetarg() : true);
X    xllastarg();
X
X    /* establish an execution context */
X    xlbegin(&cntxt,CF_ERROR,flag);
X
X    /* check for error */
X    if (setjmp(cntxt.c_jmpbuf))
X	val = NIL;
X
X    /* otherwise, evaluate the expression */
X    else {
X	expr = xleval(expr);
X	val = consa(expr);
X    }
X    xlend(&cntxt);
X
X    /* return the result */
X    return (val);
X}
X
X/* xtrace - special form 'trace' */
XLVAL xtrace()
X{
X    LVAL sym,fun,this;
X
X    /* loop through all of the arguments */
X    sym = xlenter("*TRACELIST*");
X    while (moreargs()) {
X	fun = xlgasymbol();
X
X	/* check for the function name already being in the list */
X	for (this = getvalue(sym); consp(this); this = cdr(this))
X	    if (car(this) == fun)
X		break;
X
X	/* add the function name to the list */
X	if (null(this))
X	    setvalue(sym,cons(fun,getvalue(sym)));
X    }
X    return (getvalue(sym));
X}
X
X/* xuntrace - special form 'untrace' */
XLVAL xuntrace()
X{
X    LVAL sym,fun,this,last;
X
X    /* loop through all of the arguments */
X    sym = xlenter("*TRACELIST*");
X    while (moreargs()) {
X	fun = xlgasymbol();
X
X	/* remove the function name from the list */
X	last = NIL;
X	for (this = getvalue(sym); consp(this); this = cdr(this)) {
X	    if (car(this) == fun) {
X		if (last)
X		    rplacd(last,cdr(this));
X		else
X		    setvalue(sym,cdr(this));
X		break;
X	    }
X	    last = this;
X	}
X    }
X    return (getvalue(sym));
X}
X
X/* dobindings - handle bindings for let/let*, prog/prog*, do/do* */
XLOCAL dobindings(list,env)
X  LVAL list,env;
X{
X    LVAL bnd,sym,val;
X
X    /* protect some pointers */
X    xlsave1(val);
X
X    /* bind each symbol in the list of bindings */
X    for (; consp(list); list = cdr(list)) {
X
X	/* get the next binding */
X	bnd = car(list);
X
X	/* handle a symbol */
X	if (symbolp(bnd)) {
X	    sym = bnd;
X	    val = NIL;
X	}
X
X	/* handle a list of the form (symbol expr) */
X	else if (consp(bnd)) {
X	    sym = match(SYMBOL,&bnd);
X	    val = evarg(&bnd);
X	}
X	else
X	    xlfail("bad binding");
X
X	/* bind the value to the symbol */
X	xlpbind(sym,val,env);
X    }
X
X    /* restore the stack */
X    xlpop();
X}
X
X/* doupdates - handle updates for do/do* */
XLOCAL doupdates(list,pflag)
X  LVAL list; int pflag;
X{
X    LVAL plist,bnd,sym,val;
X
X    /* protect some pointers */
X    xlstkcheck(2);
X    xlsave(plist);
X    xlsave(val);
X
X    /* bind each symbol in the list of bindings */
X    for (; consp(list); list = cdr(list)) {
X
X	/* get the next binding */
X	bnd = car(list);
X
X	/* handle a list of the form (symbol expr) */
X	if (consp(bnd)) {
X	    sym = match(SYMBOL,&bnd);
X	    bnd = cdr(bnd);
X	    if (bnd) {
X		val = evarg(&bnd);
X		if (pflag)
X		    plist = cons(cons(sym,val),plist);
X		else
X		    xlsetvalue(sym,val);
X	    }
X	}
X    }
X
X    /* set the values for parallel updates */
X    for (; plist; plist = cdr(plist))
X	xlsetvalue(car(car(plist)),cdr(car(plist)));
X
X    /* restore the stack */
X    xlpopn(2);
X}
X
X/* tagbody - execute code within a block and tagbody */
XLOCAL tagbody()
X{
X    LVAL *argv,arg;
X    CONTEXT cntxt;
X    int argc;
X
X    /* establish an execution context */
X    xlbegin(&cntxt,CF_GO,NIL);
X    argc = xlargc;
X    argv = xlargv;
X
X    /* check for a 'go' */
X    if (setjmp(cntxt.c_jmpbuf)) {
X	cntxt.c_xlargc = argc;
X	cntxt.c_xlargv = argv;
X    }
X
X    /* execute the body */
X    while (moreargs()) {
X	arg = nextarg();
X	if (consp(arg))
X	    xleval(arg);
X    }
X    xlend(&cntxt);
X}
X
X/* match - get an argument and match its type */
XLOCAL LVAL match(type,pargs)
X  int type; LVAL *pargs;
X{
X    LVAL arg;
X
X    /* make sure the argument exists */
X    if (!consp(*pargs))
X	toofew(*pargs);
X
X    /* get the argument value */
X    arg = car(*pargs);
X
X    /* move the argument pointer ahead */
X    *pargs = cdr(*pargs);
X
X    /* check its type */
X    if (type == LIST) {
X	if (arg && ntype(arg) != CONS)
X	    xlerror("bad argument type",arg);
X    }
X    else {
X	if (arg == NIL || ntype(arg) != type)
X	    xlerror("bad argument type",arg);
X    }
X
X    /* return the argument */
X    return (arg);
X}
X
X/* evarg - get the next argument and evaluate it */
XLOCAL LVAL evarg(pargs)
X  LVAL *pargs;
X{
X    LVAL arg;
X
X    /* protect some pointers */
X    xlsave1(arg);
X
X    /* make sure the argument exists */
X    if (!consp(*pargs))
X	toofew(*pargs);
X
X    /* get the argument value */
X    arg = car(*pargs);
X
X    /* move the argument pointer ahead */
X    *pargs = cdr(*pargs);
X
X    /* evaluate the argument */
X    arg = xleval(arg);
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the argument */
X    return (arg);
X}
X
X/* evmatch - get an evaluated argument and match its type */
XLOCAL LVAL evmatch(type,pargs)
X  int type; LVAL *pargs;
X{
X    LVAL arg;
X
X    /* protect some pointers */
X    xlsave1(arg);
X
X    /* make sure the argument exists */
X    if (!consp(*pargs))
X	toofew(*pargs);
X
X    /* get the argument value */
X    arg = car(*pargs);
X
X    /* move the argument pointer ahead */
X    *pargs = cdr(*pargs);
X
X    /* evaluate the argument */
X    arg = xleval(arg);
X
X    /* check its type */
X    if (type == LIST) {
X	if (arg && ntype(arg) != CONS)
X	    xlerror("bad argument type",arg);
X    }
X    else {
X	if (arg == NIL || ntype(arg) != type)
X	    xlerror("bad argument type",arg);
X    }
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the argument */
X    return (arg);
X}
X
X/* toofew - too few arguments */
XLOCAL toofew(args)
X  LVAL args;
X{
X    xlerror("too few arguments",args);
X}
X
X/* toomany - too many arguments */
XLOCAL toomany(args)
X  LVAL args;
X{
X    xlerror("too many arguments",args);
X}
X
SHAR_EOF
if test 28157 -ne "`wc -c 'xlcont.c'`"
then
	echo shar: error transmitting "'xlcont.c'" '(should have been 28157 characters)'
fi
echo shar: extracting "'xldbug.c'" '(3992 characters)'
if test -f 'xldbug.c'
then
	echo shar: over-writing existing file "'xldbug.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'xldbug.c'
X/* xldebug - xlisp debugging support */
X/*	Copyright (c) 1985, by David Michael Betz
X	All Rights Reserved
X	Permission is granted for unrestricted non-commercial use	*/
X
X#include "xlisp.h"
X
X/* external variables */
Xextern int xldebug;
Xextern int xlsample;
Xextern LVAL s_debugio,s_unbound;
Xextern LVAL s_tracenable,s_tlimit,s_breakenable;
Xextern LVAL true;
Xextern char buf[];
X
X/* external routines */
Xextern char *malloc();
X
X/* forward declarations */
XFORWARD LVAL stacktop();
X
X/* xlabort - xlisp serious error handler */
Xxlabort(emsg)
X  char *emsg;
X{
X    xlsignal(emsg,s_unbound);
X    xlerrprint("error",NULL,emsg,s_unbound);
X    xlbrklevel();
X}
X
X/* xlbreak - enter a break loop */
Xxlbreak(emsg,arg)
X  char *emsg; LVAL arg;
X{
X    breakloop("break","return from BREAK",emsg,arg,TRUE);
X}
X
X/* xlfail - xlisp error handler */
Xxlfail(emsg)
X  char *emsg;
X{
X    xlerror(emsg,s_unbound);
X}
X
X/* xlerror - handle a fatal error */
Xxlerror(emsg,arg)
X  char *emsg; LVAL arg;
X{
X    if (getvalue(s_breakenable) != NIL)
X	breakloop("error",NULL,emsg,arg,FALSE);
X    else {
X	xlsignal(emsg,arg);
X	xlerrprint("error",NULL,emsg,arg);
X	xlbrklevel();
X    }
X}
X
X/* xlcerror - handle a recoverable error */
Xxlcerror(cmsg,emsg,arg)
X  char *cmsg,*emsg; LVAL arg;
X{
X    if (getvalue(s_breakenable) != NIL)
X	breakloop("error",cmsg,emsg,arg,TRUE);
X    else {
X	xlsignal(emsg,arg);
X	xlerrprint("error",NULL,emsg,arg);
X	xlbrklevel();
X    }
X}
X
X/* xlerrprint - print an error message */
Xxlerrprint(hdr,cmsg,emsg,arg)
X  char *hdr,*cmsg,*emsg; LVAL arg;
X{
X    /* print the error message */
X    sprintf(buf,"%s: %s",hdr,emsg);
X    errputstr(buf);
X
X    /* print the argument */
X    if (arg != s_unbound) {
X	errputstr(" - ");
X	errprint(arg);
X    }
X
X    /* no argument, just end the line */
X    else
X	errputstr("\n");
X
X    /* print the continuation message */
X    if (cmsg) {
X	sprintf(buf,"if continued: %s\n",cmsg);
X	errputstr(buf);
X    }
X}
X
X/* breakloop - the debug read-eval-print loop */
XLOCAL int breakloop(hdr,cmsg,emsg,arg,cflag)
X  char *hdr,*cmsg,*emsg; LVAL arg; int cflag;
X{
X    LVAL expr,val;
X    CONTEXT cntxt;
X    int type;
X
X    /* print the error message */
X    xlerrprint(hdr,cmsg,emsg,arg);
X
X    /* flush the input buffer */
X    xlflush();
X
X    /* do the back trace */
X    if (getvalue(s_tracenable)) {
X	val = getvalue(s_tlimit);
X	xlbaktrace(fixp(val) ? (int)getfixnum(val) : -1);
X    }
X
X    /* protect some pointers */
X    xlsave1(expr);
X
X    /* increment the debug level */
X    ++xldebug;
X
X    /* debug command processing loop */
X    xlbegin(&cntxt,CF_BRKLEVEL|CF_CLEANUP|CF_CONTINUE,true);
X    for (type = 0; type == 0; ) {
X
X	/* setup the continue trap */
X	if (type = setjmp(cntxt.c_jmpbuf))
X	    switch (type) {
X	    case CF_CLEANUP:
X		continue;
X	    case CF_BRKLEVEL:
X		type = 0;
X		break;
X	    case CF_CONTINUE:
X		if (cflag) {
X		    dbgputstr("[ continue from break loop ]\n");
X		    continue;
X		}
X		else xlabort("this error can't be continued");
X	    }
X
X	/* print a prompt */
X	sprintf(buf,"%d> ",xldebug);
X	dbgputstr(buf);
X
X	/* read an expression and check for eof */
X	if (!xlread(getvalue(s_debugio),&expr,FALSE)) {
X	    type = CF_CLEANUP;
X	    break;
X	}
X
X	/* save the input expression */
X	xlrdsave(expr);
X
X	/* evaluate the expression */
X	expr = xleval(expr);
X
X	/* save the result */
X	xlevsave(expr);
X
X	/* print it */
X	dbgprint(expr);
X    }
X    xlend(&cntxt);
X
X    /* decrement the debug level */
X    --xldebug;
X
X    /* restore the stack */
X    xlpop();
X
X    /* check for aborting to the previous level */
X    if (type == CF_CLEANUP)
X	xlbrklevel();
X}
X
X/* baktrace - do a back trace */
Xxlbaktrace(n)
X  int n;
X{
X    LVAL *fp,*p;
X    int argc;
X    for (fp = xlfp; (n < 0 || n--) && *fp; fp = fp - (int)getfixnum(*fp)) {
X	p = fp + 1;
X	errputstr("Function: ");
X	errprint(*p++);
X	if (argc = (int)getfixnum(*p++))
X	    errputstr("Arguments:\n");
X	while (--argc >= 0) {
X	    errputstr("  ");
X	    errprint(*p++);
X	}
X    }
X}
X
X/* xldinit - debug initialization routine */
Xxldinit()
X{
X    xlsample = 0;
X    xldebug = 0;
X}
X
SHAR_EOF
if test 3992 -ne "`wc -c 'xldbug.c'`"
then
	echo shar: error transmitting "'xldbug.c'" '(should have been 3992 characters)'
fi
echo shar: extracting "'xldmem.c'" '(14715 characters)'
if test -f 'xldmem.c'
then
	echo shar: over-writing existing file "'xldmem.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'xldmem.c'
X/* xldmem - xlisp dynamic memory management routines */
X/*	Copyright (c) 1985, by David Michael Betz
X	All Rights Reserved
X	Permission is granted for unrestricted non-commercial use	*/
X
X#include "xlisp.h"
X
X/* node flags */
X#define MARK	1
X#define LEFT	2
X
X/* macro to compute the size of a segment */
X#define segsize(n) (sizeof(SEGMENT)+((n)-1)*sizeof(struct node))
X
X/* external variables */
Xextern LVAL obarray,s_gcflag,s_gchook,s_unbound,true;
Xextern LVAL xlenv,xlfenv,xldenv;
Xextern char buf[];
X
X/* variables local to xldmem.c and xlimage.c */
XSEGMENT *segs,*lastseg,*fixseg,*charseg;
Xint anodes,nsegs,gccalls;
Xlong nnodes,nfree,total;
XLVAL fnodes;
X
X/* external procedures */
Xextern char *malloc();
Xextern char *calloc();
X
X/* forward declarations */
XFORWARD LVAL newnode();
XFORWARD unsigned char *stralloc();
XFORWARD SEGMENT *newsegment();
X
X/* cons - construct a new cons node */
XLVAL cons(x,y)
X  LVAL x,y;
X{
X    LVAL nnode;
X
X    /* get a free node */
X    if ((nnode = fnodes) == NIL) {
X	xlstkcheck(2);
X	xlprotect(x);
X	xlprotect(y);
X	findmem();
X	if ((nnode = fnodes) == NIL)
X	    xlabort("insufficient node space");
X	xlpop();
X	xlpop();
X    }
X
X    /* unlink the node from the free list */
X    fnodes = cdr(nnode);
X    --nfree;
X
X    /* initialize the new node */
X    nnode->n_type = CONS;
X    rplaca(nnode,x);
X    rplacd(nnode,y);
X
X    /* return the new node */
X    return (nnode);
X}
X
X/* cvstring - convert a string to a string node */
XLVAL cvstring(str)
X  char *str;
X{
X    LVAL val;
X    xlsave1(val);
X    val = newnode(STRING);
X    val->n_strlen = strlen(str) + 1;
X    val->n_string = stralloc(getslength(val));
X    strcpy(getstring(val),str);
X    xlpop();
X    return (val);
X}
X
X/* newstring - allocate and initialize a new string */
XLVAL newstring(size)
X  int size;
X{
X    LVAL val;
X    xlsave1(val);
X    val = newnode(STRING);
X    val->n_strlen = size;
X    val->n_string = stralloc(getslength(val));
X    strcpy(getstring(val),"");
X    xlpop();
X    return (val);
X}
X
X/* cvsymbol - convert a string to a symbol */
XLVAL cvsymbol(pname)
X  char *pname;
X{
X    LVAL val;
X    xlsave1(val);
X    val = newvector(SYMSIZE);
X    val->n_type = SYMBOL;
X    setvalue(val,s_unbound);
X    setfunction(val,s_unbound);
X    setpname(val,cvstring(pname));
X    xlpop();
X    return (val);
X}
X
X/* cvsubr - convert a function to a subr or fsubr */
XLVAL cvsubr(fcn,type,offset)
X  LVAL (*fcn)(); int type,offset;
X{
X    LVAL val;
X    val = newnode(type);
X    val->n_subr = fcn;
X    val->n_offset = offset;
X    return (val);
X}
X
X/* cvfile - convert a file pointer to a stream */
XLVAL cvfile(fp)
X  FILE *fp;
X{
X    LVAL val;
X    val = newnode(STREAM);
X    setfile(val,fp);
X    setsavech(val,'\0');
X    return (val);
X}
X
X/* cvfixnum - convert an integer to a fixnum node */
XLVAL cvfixnum(n)
X  FIXTYPE n;
X{
X    LVAL val;
X    if (n >= SFIXMIN && n <= SFIXMAX)
X	return (&fixseg->sg_nodes[(int)n-SFIXMIN]);
X    val = newnode(FIXNUM);
X    val->n_fixnum = n;
X    return (val);
X}
X
X/* cvflonum - convert a floating point number to a flonum node */
XLVAL cvflonum(n)
X  FLOTYPE n;
X{
X    LVAL val;
X    val = newnode(FLONUM);
X    val->n_flonum = n;
X    return (val);
X}
X
X/* cvchar - convert an integer to a character node */
XLVAL cvchar(n)
X  int n;
X{
X    if (n >= CHARMIN && n <= CHARMAX)
X	return (&charseg->sg_nodes[n-CHARMIN]);
X    xlerror("character code out of range",cvfixnum((FIXTYPE)n));
X}
X
X/* newustream - create a new unnamed stream */
XLVAL newustream()
X{
X    LVAL val;
X    val = newnode(USTREAM);
X    sethead(val,NIL);
X    settail(val,NIL);
X    return (val);
X}
X
X/* newobject - allocate and initialize a new object */
XLVAL newobject(cls,size)
X  LVAL cls; int size;
X{
X    LVAL val;
X    val = newvector(size+1);
X    val->n_type = OBJECT;
X    setelement(val,0,cls);
X    return (val);
X}
X
X/* newclosure - allocate and initialize a new closure */
XLVAL newclosure(name,type,env,fenv)
X  LVAL name,type,env,fenv;
X{
X    LVAL val;
X    val = newvector(CLOSIZE);
X    val->n_type = CLOSURE;
X    setname(val,name);
X    settype(val,type);
X    setenv(val,env);
X    setfenv(val,fenv);
X    return (val);
X}
X
X/* newstruct - allocate and initialize a new structure node */
XLVAL newstruct(type,size)
X  LVAL type; int size;
X{
X    LVAL val;
X    val = newvector(size+1);
X    val->n_type = STRUCT;
X    setelement(val,0,type);
X    return (val);
X}
X
X/* newvector - allocate and initialize a new vector node */
XLVAL newvector(size)
X  int size;
X{
X    LVAL vect;
X    int bsize;
X    xlsave1(vect);
X    vect = newnode(VECTOR);
X    vect->n_vsize = 0;
X    if (bsize = size * sizeof(LVAL)) {
X	if ((vect->n_vdata = (LVAL *)calloc(1,bsize)) == NULL) {
X	    findmem();
X	    if ((vect->n_vdata = (LVAL *)calloc(1,bsize)) == NULL)
X		xlfail("insufficient vector space");
X	}
X	vect->n_vsize = size;
X	total += (long) bsize;
X    }
X    xlpop();
X    return (vect);
X}
X
X/* newnode - allocate a new node */
XLOCAL LVAL newnode(type)
X  int type;
X{
X    LVAL nnode;
X
X    /* get a free node */
X    if ((nnode = fnodes) == NIL) {
X	findmem();
X	if ((nnode = fnodes) == NIL)
X	    xlabort("insufficient node space");
X    }
X
X    /* unlink the node from the free list */
X    fnodes = cdr(nnode);
X    nfree -= 1L;
X
X    /* initialize the new node */
X    nnode->n_type = type;
X    rplacd(nnode,NIL);
X
X    /* return the new node */
X    return (nnode);
X}
X
X/* stralloc - allocate memory for a string adding a byte for the terminator */
XLOCAL unsigned char *stralloc(size)
X  int size;
X{
X    unsigned char *sptr;
X
X    /* allocate memory for the string copy */
X    if ((sptr = (unsigned char *)malloc(size)) == NULL) {
X	gc();  
X	if ((sptr = (unsigned char *)malloc(size)) == NULL)
X	    xlfail("insufficient string space");
X    }
X    total += (long)size;
X
X    /* return the new string memory */
X    return (sptr);
X}
X
X/* findmem - find more memory by collecting then expanding */
XLOCAL findmem()
X{
X    gc();
X    if (nfree < (long)anodes)
X	addseg();
X}
X
X/* gc - garbage collect (only called here and in xlimage.c) */
Xgc()
X{
X    register LVAL **p,*ap,tmp;
X    char buf[STRMAX+1];
X    LVAL *newfp,fun;
X
X    /* print the start of the gc message */
X    if (s_gcflag && getvalue(s_gcflag)) {
X	sprintf(buf,"[ gc: total %ld, ",nnodes);
X	stdputstr(buf);
X    }
X
X    /* mark the obarray, the argument list and the current environment */
X    if (obarray)
X	mark(obarray);
X    if (xlenv)
X	mark(xlenv);
X    if (xlfenv)
X	mark(xlfenv);
X    if (xldenv)
X	mark(xldenv);
X
X    /* mark the evaluation stack */
X    for (p = xlstack; p < xlstktop; ++p)
X	if (tmp = **p)
X	    mark(tmp);
X
X    /* mark the argument stack */
X    for (ap = xlargstkbase; ap < xlsp; ++ap)
X	if (tmp = *ap)
X	    mark(tmp);
X
X    /* sweep memory collecting all unmarked nodes */
X    sweep();
X
X    /* count the gc call */
X    ++gccalls;
X
X    /* call the *gc-hook* if necessary */
X    if (s_gchook && (fun = getvalue(s_gchook))) {
X	newfp = xlsp;
X	pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
X	pusharg(fun);
X	pusharg(cvfixnum((FIXTYPE)2));
X	pusharg(cvfixnum((FIXTYPE)nnodes));
X	pusharg(cvfixnum((FIXTYPE)nfree));
X	xlfp = newfp;
X	xlapply(2);
X    }
X
X    /* print the end of the gc message */
X    if (s_gcflag && getvalue(s_gcflag)) {
X	sprintf(buf,"%ld free ]\n",nfree);
X	stdputstr(buf);
X    }
X}
X
X/* mark - mark all accessible nodes */
XLOCAL mark(ptr)
X  LVAL ptr;
X{
X    register LVAL this,prev,tmp;
X    int type,i,n;
X
X    /* initialize */
X    prev = NIL;
X    this = ptr;
X
X    /* mark this list */
X    for (;;) {
X
X	/* descend as far as we can */
X	while (!(this->n_flags & MARK))
X
X	    /* check cons and unnamed stream nodes */
X	    if ((type = ntype(this)) == CONS || type == USTREAM) {
X		if (tmp = car(this)) {
X		    this->n_flags |= MARK|LEFT;
X		    rplaca(this,prev);
X		}
X		else if (tmp = cdr(this)) {
X		    this->n_flags |= MARK;
X		    rplacd(this,prev);
X		}
X		else {				/* both sides nil */
X		    this->n_flags |= MARK;
X		    break;
X		}
X		prev = this;			/* step down the branch */
X		this = tmp;
X	    }
X
X	    /* mark other node types */
X	    else {
X		this->n_flags |= MARK;
X		switch (type) {
X		case SYMBOL:
X		case OBJECT:
X		case VECTOR:
X		case CLOSURE:
X		case STRUCT:
X		    for (i = 0, n = getsize(this); --n >= 0; ++i)
X			if (tmp = getelement(this,i))
X			    mark(tmp);
X		    break;
X		}
X		break;
X	    }
X
X	/* backup to a point where we can continue descending */
X	for (;;)
X
X	    /* make sure there is a previous node */
X	    if (prev) {
X		if (prev->n_flags & LEFT) {	/* came from left side */
X		    prev->n_flags &= ~LEFT;
X		    tmp = car(prev);
X		    rplaca(prev,this);
X		    if (this = cdr(prev)) {
X			rplacd(prev,tmp);			
X			break;
X		    }
X		}
X		else {				/* came from right side */
X		    tmp = cdr(prev);
X		    rplacd(prev,this);
X		}
X		this = prev;			/* step back up the branch */
X		prev = tmp;
X	    }
X
X	    /* no previous node, must be done */
X	    else
X		return;
X    }
X}
X
X/* sweep - sweep all unmarked nodes and add them to the free list */
XLOCAL sweep()
X{
X    SEGMENT *seg;
X    LVAL p;
X    int n;
X
X    /* empty the free list */
X    fnodes = NIL;
X    nfree = 0L;
X
X    /* add all unmarked nodes */
X    for (seg = segs; seg; seg = seg->sg_next) {
X	if (seg == fixseg)	 /* don't sweep the fixnum segment */
X	    continue;
X	else if (seg == charseg) /* don't sweep the character segment */
X	    continue;
X	p = &seg->sg_nodes[0];
X	for (n = seg->sg_size; --n >= 0; ++p)
X	    if (!(p->n_flags & MARK)) {
X		switch (ntype(p)) {
X		case STRING:
X			if (getstring(p) != NULL) {
X			    total -= (long)getslength(p);
X			    free(getstring(p));
X			}
X			break;
X		case STREAM:
X			if (getfile(p))
X			    osclose(getfile(p));
X			break;
X		case SYMBOL:
X		case OBJECT:
X		case VECTOR:
X		case CLOSURE:
X		case STRUCT:
X			if (p->n_vsize) {
X			    total -= (long) (p->n_vsize * sizeof(LVAL));
X			    free(p->n_vdata);
X			}
X			break;
X		}
X		p->n_type = FREE;
X		rplaca(p,NIL);
X		rplacd(p,fnodes);
X		fnodes = p;
X		nfree += 1L;
X	    }
X	    else
X		p->n_flags &= ~MARK;
X    }
X}
X
X/* addseg - add a segment to the available memory */
XLOCAL int addseg()
X{
X    SEGMENT *newseg;
X    LVAL p;
X    int n;
X
X    /* allocate the new segment */
X    if (anodes == 0 || (newseg = newsegment(anodes)) == NULL)
X	return (FALSE);
X
X    /* add each new node to the free list */
X    p = &newseg->sg_nodes[0];
X    for (n = anodes; --n >= 0; ++p) {
X	rplacd(p,fnodes);
X	fnodes = p;
X    }
X
X    /* return successfully */
X    return (TRUE);
X}
X
X/* newsegment - create a new segment (only called here and in xlimage.c) */
XSEGMENT *newsegment(n)
X  int n;
X{
X    SEGMENT *newseg;
X
X    /* allocate the new segment */
X    if ((newseg = (SEGMENT *)calloc(1,segsize(n))) == NULL)
X	return (NULL);
X
X    /* initialize the new segment */
X    newseg->sg_size = n;
X    newseg->sg_next = NULL;
X    if (segs)
X	lastseg->sg_next = newseg;
X    else
X	segs = newseg;
X    lastseg = newseg;
X
X    /* update the statistics */
X    total += (long)segsize(n);
X    nnodes += (long)n;
X    nfree += (long)n;
X    ++nsegs;
X
X    /* return the new segment */
X    return (newseg);
X}
X 
X/* stats - print memory statistics */
XLOCAL stats()
X{
X    sprintf(buf,"Nodes:       %ld\n",nnodes); stdputstr(buf);
X    sprintf(buf,"Free nodes:  %ld\n",nfree);  stdputstr(buf);
X    sprintf(buf,"Segments:    %d\n",nsegs);   stdputstr(buf);
X    sprintf(buf,"Allocate:    %d\n",anodes);  stdputstr(buf);
X    sprintf(buf,"Total:       %ld\n",total);  stdputstr(buf);
X    sprintf(buf,"Collections: %d\n",gccalls); stdputstr(buf);
X}
X
X/* xgc - xlisp function to force garbage collection */
XLVAL xgc()
X{
X    /* make sure there aren't any arguments */
X    xllastarg();
X
X    /* garbage collect */
X    gc();
X
X    /* return nil */
X    return (NIL);
X}
X
X/* xexpand - xlisp function to force memory expansion */
XLVAL xexpand()
X{
X    LVAL num;
X    int n,i;
X
X    /* get the new number to allocate */
X    if (moreargs()) {
X	num = xlgafixnum();
X	n = getfixnum(num);
X    }
X    else
X	n = 1;
X    xllastarg();
X
X    /* allocate more segments */
X    for (i = 0; i < n; i++)
X	if (!addseg())
X	    break;
X
X    /* return the number of segments added */
X    return (cvfixnum((FIXTYPE)i));
X}
X
X/* xalloc - xlisp function to set the number of nodes to allocate */
XLVAL xalloc()
X{
X    int n,oldn;
X    LVAL num;
X
X    /* get the new number to allocate */
X    num = xlgafixnum();
X    n = getfixnum(num);
X
X    /* make sure there aren't any more arguments */
X    xllastarg();
X
X    /* set the new number of nodes to allocate */
X    oldn = anodes;
X    anodes = n;
X
X    /* return the old number */
X    return (cvfixnum((FIXTYPE)oldn));
X}
X
X/* xmem - xlisp function to print memory statistics */
XLVAL xmem()
X{
X    /* allow one argument for compatiblity with common lisp */
X    if (moreargs()) xlgetarg();
X    xllastarg();
X
X    /* print the statistics */
X    stats();
X
X    /* return nil */
X    return (NIL);
X}
X
X#ifdef SAVERESTORE
X/* xsave - save the memory image */
XLVAL xsave()
X{
X    unsigned char *name;
X
X    /* get the file name, verbose flag and print flag */
X    name = getstring(xlgetfname());
X    xllastarg();
X
X    /* save the memory image */
X    return (xlisave(name) ? true : NIL);
X}
X
X/* xrestore - restore a saved memory image */
XLVAL xrestore()
X{
X    extern jmp_buf top_level;
X    unsigned char *name;
X
X    /* get the file name, verbose flag and print flag */
X    name = getstring(xlgetfname());
X    xllastarg();
X
X    /* restore the saved memory image */
X    if (!xlirestore(name))
X	return (NIL);
X
X    /* return directly to the top level */
X    stdputstr("[ returning to the top level ]\n");
X    longjmp(top_level,1);
X}
X#endif
X
X/* xlminit - initialize the dynamic memory module */
Xxlminit()
X{
X    LVAL p;
X    int i;
X
X    /* initialize our internal variables */
X    segs = lastseg = NULL;
X    nnodes = nfree = total = 0L;
X    nsegs = gccalls = 0;
X    anodes = NNODES;
X    fnodes = NIL;
X
X    /* allocate the fixnum segment */
X    if ((fixseg = newsegment(SFIXSIZE)) == NULL)
X	xlfatal("insufficient memory");
X
X    /* initialize the fixnum segment */
X    p = &fixseg->sg_nodes[0];
X    for (i = SFIXMIN; i <= SFIXMAX; ++i) {
X	p->n_type = FIXNUM;
X	p->n_fixnum = i;
X	++p;
X    }
X
X    /* allocate the character segment */
X    if ((charseg = newsegment(CHARSIZE)) == NULL)
X	xlfatal("insufficient memory");
X
X    /* initialize the character segment */
X    p = &charseg->sg_nodes[0];
X    for (i = CHARMIN; i <= CHARMAX; ++i) {
X	p->n_type = CHAR;
X	p->n_chcode = i;
X	++p;
X    }
X
X    /* initialize structures that are marked by the collector */
X    obarray = xlenv = xlfenv = xldenv = NIL;
X    s_gcflag = s_gchook = NIL;
X
X    /* allocate the evaluation stack */
X    if ((xlstkbase = (LVAL **)malloc(EDEPTH * sizeof(LVAL *))) == NULL)
X	xlfatal("insufficient memory");
X    xlstack = xlstktop = xlstkbase + EDEPTH;
X
X    /* allocate the argument stack */
X    if ((xlargstkbase = (LVAL *)malloc(ADEPTH * sizeof(LVAL))) == NULL)
X	xlfatal("insufficient memory");
X    xlargstktop = xlargstkbase + ADEPTH;
X    xlfp = xlsp = xlargstkbase;
X    *xlsp++ = NIL;
X}
X
SHAR_EOF
if test 14715 -ne "`wc -c 'xldmem.c'`"
then
	echo shar: error transmitting "'xldmem.c'" '(should have been 14715 characters)'
fi
echo shar: extracting "'xldmem.h'" '(6120 characters)'
if test -f 'xldmem.h'
then
	echo shar: over-writing existing file "'xldmem.h'"
fi
sed 's/^X//' << \SHAR_EOF > 'xldmem.h'
X/* xldmem.h - dynamic memory definitions */
X/*	Copyright (c) 1987, by David Michael Betz
X	All Rights Reserved
X	Permission is granted for unrestricted non-commercial use	*/
X
X/* small fixnum range */
X#define SFIXMIN		(-128)
X#define SFIXMAX		255
X#define SFIXSIZE	384
X
X/* character range */
X#define CHARMIN		0
X#define CHARMAX		255
X#define CHARSIZE	256
X
X/* new node access macros */
X#define ntype(x)	((x)->n_type)
X
X/* cons access macros */
X#define car(x)		((x)->n_car)
X#define cdr(x)		((x)->n_cdr)
X#define rplaca(x,y)	((x)->n_car = (y))
X#define rplacd(x,y)	((x)->n_cdr = (y))
X
X/* symbol access macros */
X#define getvalue(x)	 ((x)->n_vdata[0])
X#define setvalue(x,v)	 ((x)->n_vdata[0] = (v))
X#define getfunction(x)	 ((x)->n_vdata[1])
X#define setfunction(x,v) ((x)->n_vdata[1] = (v))
X#define getplist(x)	 ((x)->n_vdata[2])
X#define setplist(x,v)	 ((x)->n_vdata[2] = (v))
X#define getpname(x)	 ((x)->n_vdata[3])
X#define setpname(x,v)	 ((x)->n_vdata[3] = (v))
X#define SYMSIZE		4
X
X/* closure access macros */
X#define getname(x)     	((x)->n_vdata[0])
X#define setname(x,v)   	((x)->n_vdata[0] = (v))
X#define gettype(x)    	((x)->n_vdata[1])
X#define settype(x,v)  	((x)->n_vdata[1] = (v))
X#define getargs(x)     	((x)->n_vdata[2])
X#define setargs(x,v)   	((x)->n_vdata[2] = (v))
X#define getoargs(x)    	((x)->n_vdata[3])
X#define setoargs(x,v)  	((x)->n_vdata[3] = (v))
X#define getrest(x)     	((x)->n_vdata[4])
X#define setrest(x,v)   	((x)->n_vdata[4] = (v))
X#define getkargs(x)    	((x)->n_vdata[5])
X#define setkargs(x,v)  	((x)->n_vdata[5] = (v))
X#define getaargs(x)    	((x)->n_vdata[6])
X#define setaargs(x,v)  	((x)->n_vdata[6] = (v))
X#define getbody(x)     	((x)->n_vdata[7])
X#define setbody(x,v)   	((x)->n_vdata[7] = (v))
X#define getenv(x)	((x)->n_vdata[8])
X#define setenv(x,v)	((x)->n_vdata[8] = (v))
X#define getfenv(x)	((x)->n_vdata[9])
X#define setfenv(x,v)	((x)->n_vdata[9] = (v))
X#define getlambda(x)	((x)->n_vdata[10])
X#define setlambda(x,v)	((x)->n_vdata[10] = (v))
X#define CLOSIZE		11
X
X/* vector access macros */
X#define getsize(x)	((x)->n_vsize)
X#define getelement(x,i)	((x)->n_vdata[i])
X#define setelement(x,i,v) ((x)->n_vdata[i] = (v))
X
X/* object access macros */
X#define getclass(x)	((x)->n_vdata[0])
X#define getivar(x,i)	((x)->n_vdata[i+1])
X#define setivar(x,i,v)	((x)->n_vdata[i+1] = (v))
X
X/* subr/fsubr access macros */
X#define getsubr(x)	((x)->n_subr)
X#define getoffset(x)	((x)->n_offset)
X
X/* fixnum/flonum/char access macros */
X#define getfixnum(x)    ((x)->n_fixnum)
X#define getflonum(x)	((x)->n_flonum)
X#define getchcode(x)	((x)->n_chcode)
X
X/* string access macros */
X#define getstring(x)	((x)->n_string)
X#define getslength(x)	((x)->n_strlen)
X
X/* file stream access macros */
X#define getfile(x)	((x)->n_fp)
X#define setfile(x,v)	((x)->n_fp = (v))
X#define getsavech(x)	((x)->n_savech)
X#define setsavech(x,v)	((x)->n_savech = (v))
X
X/* unnamed stream access macros */
X#define gethead(x)	((x)->n_car)
X#define sethead(x,v)	((x)->n_car = (v))
X#define gettail(x)	((x)->n_cdr)
X#define settail(x,v)	((x)->n_cdr = (v))
X
X/* node types */
X#define FREE	0
X#define SUBR	1
X#define FSUBR	2
X#define CONS	3
X#define SYMBOL	4
X#define FIXNUM	5
X#define FLONUM	6
X#define STRING	7
X#define OBJECT	8
X#define STREAM	9
X#define VECTOR	10
X#define CLOSURE	11
X#define CHAR	12
X#define USTREAM	13
X#define STRUCT	14
X
X/* subr/fsubr node */
X#define n_subr		n_info.n_xsubr.xs_subr
X#define n_offset	n_info.n_xsubr.xs_offset
X
X/* cons node */
X#define n_car		n_info.n_xcons.xc_car
X#define n_cdr		n_info.n_xcons.xc_cdr
X
X/* fixnum node */
X#define n_fixnum	n_info.n_xfixnum.xf_fixnum
X
X/* flonum node */
X#define n_flonum	n_info.n_xflonum.xf_flonum
X/* character node */
X#define n_chcode	n_info.n_xchar.xc_chcode
X
X/* string node */
X#define n_string	n_info.n_xstring.xs_string
X#define n_strlen	n_info.n_xstring.xs_length
X
X/* stream node */
X#define n_fp		n_info.n_xstream.xs_fp
X#define n_savech	n_info.n_xstream.xs_savech
X
X/* vector/object node */
X#define n_vsize		n_info.n_xvector.xv_size
X#define n_vdata		n_info.n_xvector.xv_data
X
X/* node structure */
Xtypedef struct node {
X    char n_type;		/* type of node */
X    char n_flags;		/* flag bits */
X    union ninfo { 		/* value */
X	struct xsubr {		/* subr/fsubr node */
X	    struct node *(*xs_subr)();	/* function pointer */
X	    int xs_offset;		/* offset into funtab */
X	} n_xsubr;
X	struct xcons {		/* cons node */
X	    struct node *xc_car;	/* the car pointer */
X	    struct node *xc_cdr;	/* the cdr pointer */
X	} n_xcons;
X	struct xfixnum {	/* fixnum node */
X	    FIXTYPE xf_fixnum;		/* fixnum value */
X	} n_xfixnum;
X	struct xflonum {	/* flonum node */
X	    FLOTYPE xf_flonum;		/* flonum value */
X	} n_xflonum;
X	struct xchar {		/* character node */
X	    int xc_chcode;		/* character code */
X	} n_xchar;
X	struct xstring {	/* string node */
X	    int xs_length;		/* string length */
X	    unsigned char *xs_string;	/* string pointer */
X	} n_xstring;
X	struct xstream { 	/* stream node */
X	    FILE *xs_fp;		/* the file pointer */
X	    int xs_savech;		/* lookahead character */
X	} n_xstream;
X	struct xvector {	/* vector/object/symbol/structure node */
X	    int xv_size;		/* vector size */
X	    struct node **xv_data;	/* vector data */
X	} n_xvector;
X    } n_info;
X} *LVAL;
X
X/* memory segment structure definition */
Xtypedef struct segment {
X    int sg_size;
X    struct segment *sg_next;
X    struct node sg_nodes[1];
X} SEGMENT;
X
X/* memory allocation functions */
Xextern LVAL cons();		/* (cons x y) */
Xextern LVAL cvsymbol();       	/* convert a string to a symbol */
Xextern LVAL cvstring();       	/* convert a string */
Xextern LVAL cvfile();		/* convert a FILE * to a file */
Xextern LVAL cvsubr();		/* convert a function to a subr/fsubr */
Xextern LVAL cvfixnum();       	/* convert a fixnum */
Xextern LVAL cvflonum();       	/* convert a flonum */
Xextern LVAL cvchar();		/* convert a character */
X
Xextern LVAL newstring();	/* create a new string */
Xextern LVAL newvector();	/* create a new vector */
Xextern LVAL newobject();	/* create a new object */
Xextern LVAL newclosure();	/* create a new closure */
Xextern LVAL newustream();	/* create a new unnamed stream */
Xextern LVAL newstruct();	/* create a new structure */
X
SHAR_EOF
if test 6120 -ne "`wc -c 'xldmem.h'`"
then
	echo shar: error transmitting "'xldmem.h'" '(should have been 6120 characters)'
fi
echo shar: extracting "'xleval.c'" '(19240 characters)'
if test -f 'xleval.c'
then
	echo shar: over-writing existing file "'xleval.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'xleval.c'
X/* xleval - xlisp evaluator */
X/*	Copyright (c) 1985, by David Michael Betz
X	All Rights Reserved
X	Permission is granted for unrestricted non-commercial use	*/
X
X#include "xlisp.h"
X
X/* macro to check for lambda list keywords */
X#define iskey(s) ((s) == lk_optional \
X               || (s) == lk_rest \
X               || (s) == lk_key \
X               || (s) == lk_aux \
X               || (s) == lk_allow_other_keys)
X
X/* macros to handle tracing */
X#define trenter(sym,argc,argv) {if (sym) doenter(sym,argc,argv);}
X#define trexit(sym,val) {if (sym) doexit(sym,val);}
X
X/* external variables */
Xextern LVAL xlenv,xlfenv,xldenv,xlvalue,true;
Xextern LVAL lk_optional,lk_rest,lk_key,lk_aux,lk_allow_other_keys;
Xextern LVAL s_evalhook,s_applyhook,s_tracelist;
Xextern LVAL s_lambda,s_macro;
Xextern LVAL s_unbound;
Xextern int xlsample;
Xextern char buf[];
X
X/* forward declarations */
XFORWARD LVAL xlxeval();
XFORWARD LVAL evalhook();
XFORWARD LVAL evform();
XFORWARD LVAL evfun();
X
X/* xleval - evaluate an xlisp expression (checking for *evalhook*) */
XLVAL xleval(expr)
X  LVAL expr;
X{
X    /* check for control codes */
X    if (--xlsample <= 0) {
X	xlsample = SAMPLE;
X	oscheck();
X    }
X
X    /* check for *evalhook* */
X    if (getvalue(s_evalhook))
X	return (evalhook(expr));
X
X    /* check for nil */
X    if (null(expr))
X	return (NIL);
X
X    /* dispatch on the node type */
X    switch (ntype(expr)) {
X    case CONS:
X	return (evform(expr));
X    case SYMBOL:
X	return (xlgetvalue(expr));
X    default:
X	return (expr);
X    }
X}
X
X/* xlevalenv - evaluate an expression in a specified environment */
XLVAL xlevalenv(expr,env,fenv)
X  LVAL expr,env,fenv;
X{
X    LVAL oldenv,oldfenv,val;
X
X    /* protect some pointers */
X    xlstkcheck(2);
X    xlsave(oldenv);
X    xlsave(oldfenv);
X
X    /* establish the new environment */
X    oldenv = xlenv;
X    oldfenv = xlfenv;
X    xlenv = env;
X    xlfenv = fenv;
X
X    /* evaluate the expression */
X    val = xleval(expr);
X
X    /* restore the environment */
X    xlenv = oldenv;
X    xlfenv = oldfenv;
X
X    /* restore the stack */
X    xlpopn(2);
X
X    /* return the result value */
X    return (val);
X}
X
X/* xlxeval - evaluate an xlisp expression (bypassing *evalhook*) */
XLVAL xlxeval(expr)
X  LVAL expr;
X{
X    /* check for nil */
X    if (null(expr))
X	return (NIL);
X
X    /* dispatch on node type */
X    switch (ntype(expr)) {
X    case CONS:
X	return (evform(expr));
X    case SYMBOL:
X	return (xlgetvalue(expr));
X    default:
X	return (expr);
X    }
X}
X
X/* xlapply - apply a function to arguments (already on the stack) */
XLVAL xlapply(argc)
X  int argc;
X{
X    LVAL *oldargv,fun,val;
X    int oldargc;
X    
X    /* get the function */
X    fun = xlfp[1];
X
X    /* get the functional value of symbols */
X    if (symbolp(fun)) {
X	while ((val = getfunction(fun)) == s_unbound)
X	    xlfunbound(fun);
X	fun = xlfp[1] = val;
X    }
X
X    /* check for nil */
X    if (null(fun))
X	xlerror("bad function",fun);
X
X    /* dispatch on node type */
X    switch (ntype(fun)) {
X    case SUBR:
X	oldargc = xlargc;
X	oldargv = xlargv;
X	xlargc = argc;
X	xlargv = xlfp + 3;
X	val = (*getsubr(fun))();
X	xlargc = oldargc;
X	xlargv = oldargv;
X	break;
X    case CONS:
X	if (!consp(cdr(fun)))
X	    xlerror("bad function",fun);
X	if (car(fun) == s_lambda)
X	    fun = xlclose(NIL,
X	                  s_lambda,
X	                  car(cdr(fun)),
X	                  cdr(cdr(fun)),
X	                  xlenv,xlfenv);
X	else
X	    xlerror("bad function",fun);
X	/**** fall through into the next case ****/
X    case CLOSURE:
X	if (gettype(fun) != s_lambda)
X	    xlerror("bad function",fun);
X	val = evfun(fun,argc,xlfp+3);
X	break;
X    default:
X	xlerror("bad function",fun);
X    }
X
X    /* remove the call frame */
X    xlsp = xlfp;
X    xlfp = xlfp - (int)getfixnum(*xlfp);
X
X    /* return the function value */
X    return (val);
X}
X
X/* evform - evaluate a form */
XLOCAL LVAL evform(form)
X  LVAL form;
X{
X    LVAL fun,args,val,type;
X    LVAL tracing=NIL;
X    LVAL *argv;
X    int argc;
X
X    /* protect some pointers */
X    xlstkcheck(2);
X    xlsave(fun);
X    xlsave(args);
X
X    /* get the function and the argument list */
X    fun = car(form);
X    args = cdr(form);
X
X    /* get the functional value of symbols */
X    if (symbolp(fun)) {
X	if (getvalue(s_tracelist) && member(fun,getvalue(s_tracelist)))
X	    tracing = fun;
X	fun = xlgetfunction(fun);
X    }
X
X    /* check for nil */
X    if (null(fun))
X	xlerror("bad function",NIL);
X
X    /* dispatch on node type */
X    switch (ntype(fun)) {
X    case SUBR:
X	argv = xlargv;
X	argc = xlargc;
X	xlargc = evpushargs(fun,args);
X	xlargv = xlfp + 3;
X	trenter(tracing,xlargc,xlargv);
X	val = (*getsubr(fun))();
X	trexit(tracing,val);
X	xlsp = xlfp;
X	xlfp = xlfp - (int)getfixnum(*xlfp);
X	xlargv = argv;
X	xlargc = argc;
X	break;
X    case FSUBR:
X	argv = xlargv;
X	argc = xlargc;
X	xlargc = pushargs(fun,args);
X	xlargv = xlfp + 3;
X	val = (*getsubr(fun))();
X	xlsp = xlfp;
X	xlfp = xlfp - (int)getfixnum(*xlfp);
X	xlargv = argv;
X	xlargc = argc;
X	break;
X    case CONS:
X	if (!consp(cdr(fun)))
X	    xlerror("bad function",fun);
X	if ((type = car(fun)) == s_lambda)
X 	    fun = xlclose(NIL,
X 	                  s_lambda,
X 	                  car(cdr(fun)),
X 	                  cdr(cdr(fun)),
X 	                  xlenv,xlfenv);
X	else
X	    xlerror("bad function",fun);
X	/**** fall through into the next case ****/
X    case CLOSURE:
X	if (gettype(fun) == s_lambda) {
X	    argc = evpushargs(fun,args);
X	    argv = xlfp + 3;
X	    trenter(tracing,argc,argv);
X	    val = evfun(fun,argc,argv);
X	    trexit(tracing,val);
X	    xlsp = xlfp;
X	    xlfp = xlfp - (int)getfixnum(*xlfp);
X	}
X	else {
X	    macroexpand(fun,args,&fun);
X	    val = xleval(fun);
X	}
X	break;
X    default:
X	xlerror("bad function",fun);
X    }
X
X    /* restore the stack */
X    xlpopn(2);
X
X    /* return the result value */
X    return (val);
X}
X
X/* xlexpandmacros - expand macros in a form */
XLVAL xlexpandmacros(form)
X  LVAL form;
X{
X    LVAL fun,args;
X    
X    /* protect some pointers */
X    xlstkcheck(3);
X    xlprotect(form);
X    xlsave(fun);
X    xlsave(args);
X
X    /* expand until the form isn't a macro call */
X    while (consp(form)) {
X	fun = car(form);		/* get the macro name */
X	args = cdr(form);		/* get the arguments */
X	if (!symbolp(fun) || !fboundp(fun))
X	    break;
X	fun = xlgetfunction(fun);	/* get the expansion function */
X	if (!macroexpand(fun,args,&form))
X	    break;
X    }
X
X    /* restore the stack and return the expansion */
X    xlpopn(3);
X    return (form);
X}
X
X/* macroexpand - expand a macro call */
Xint macroexpand(fun,args,pval)
X  LVAL fun,args,*pval;
X{
X    LVAL *argv;
X    int argc;
X    
X    /* make sure it's really a macro call */
X    if (!closurep(fun) || gettype(fun) != s_macro)
X	return (FALSE);
X	
X    /* call the expansion function */
X    argc = pushargs(fun,args);
X    argv = xlfp + 3;
X    *pval = evfun(fun,argc,argv);
X    xlsp = xlfp;
X    xlfp = xlfp - (int)getfixnum(*xlfp);
X    return (TRUE);
X}
X
X/* evalhook - call the evalhook function */
XLOCAL LVAL evalhook(expr)
X  LVAL expr;
X{
X    LVAL *newfp,olddenv,val;
X
X    /* create the new call frame */
X    newfp = xlsp;
X    pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
X    pusharg(getvalue(s_evalhook));
X    pusharg(cvfixnum((FIXTYPE)2));
X    pusharg(expr);
X    pusharg(cons(xlenv,xlfenv));
X    xlfp = newfp;
X
X    /* rebind the hook functions to nil */
X    olddenv = xldenv;
X    xldbind(s_evalhook,NIL);
X    xldbind(s_applyhook,NIL);
X
X    /* call the hook function */
X    val = xlapply(2);
X
X    /* unbind the symbols */
X    xlunbind(olddenv);
X
X    /* return the value */
X    return (val);
X}
X
X/* evpushargs - evaluate and push a list of arguments */
XLOCAL int evpushargs(fun,args)
X  LVAL fun,args;
X{
X    LVAL *newfp;
X    int argc;
X    
X    /* protect the argument list */
X    xlprot1(args);
X
X    /* build a new argument stack frame */
X    newfp = xlsp;
X    pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
X    pusharg(fun);
X    pusharg(NIL); /* will be argc */
X
X    /* evaluate and push each argument */
X    for (argc = 0; consp(args); args = cdr(args), ++argc)
X	pusharg(xleval(car(args)));
X
X    /* establish the new stack frame */
X    newfp[2] = cvfixnum((FIXTYPE)argc);
X    xlfp = newfp;
X    
X    /* restore the stack */
X    xlpop();
X
X    /* return the number of arguments */
X    return (argc);
X}
X
X/* pushargs - push a list of arguments */
Xint pushargs(fun,args)
X  LVAL fun,args;
X{
X    LVAL *newfp;
X    int argc;
X    
X    /* build a new argument stack frame */
X    newfp = xlsp;
X    pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
X    pusharg(fun);
X    pusharg(NIL); /* will be argc */
X
X    /* push each argument */
X    for (argc = 0; consp(args); args = cdr(args), ++argc)
X	pusharg(car(args));
X
X    /* establish the new stack frame */
X    newfp[2] = cvfixnum((FIXTYPE)argc);
X    xlfp = newfp;
X
X    /* return the number of arguments */
X    return (argc);
X}
X
X/* makearglist - make a list of the remaining arguments */
XLVAL makearglist(argc,argv)
X  int argc; LVAL *argv;
X{
X    LVAL list,this,last;
X    xlsave1(list);
X    for (last = NIL; --argc >= 0; last = this) {
X	this = cons(*argv++,NIL);
X	if (last) rplacd(last,this);
X	else list = this;
X	last = this;
X    }
X    xlpop();
X    return (list);
X}
X
X/* evfun - evaluate a function */
XLOCAL LVAL evfun(fun,argc,argv)
X  LVAL fun; int argc; LVAL *argv;
X{
X    LVAL oldenv,oldfenv,cptr,name,val;
X    CONTEXT cntxt;
X
X    /* protect some pointers */
X    xlstkcheck(3);
X    xlsave(oldenv);
X    xlsave(oldfenv);
X    xlsave(cptr);
X
X    /* create a new environment frame */
X    oldenv = xlenv;
X    oldfenv = xlfenv;
X    xlenv = xlframe(getenv(fun));
X    xlfenv = getfenv(fun);
X
X    /* bind the formal parameters */
X    xlabind(fun,argc,argv);
X
X    /* setup the implicit block */
X    if (name = getname(fun))
X	xlbegin(&cntxt,CF_RETURN,name);
X
X    /* execute the block */
X    if (name && setjmp(cntxt.c_jmpbuf))
X	val = xlvalue;
X    else
X	for (val = NIL, cptr = getbody(fun); consp(cptr); cptr = cdr(cptr))
X	    val = xleval(car(cptr));
X
X    /* finish the block context */
X    if (name)
X	xlend(&cntxt);
X
X    /* restore the environment */
X    xlenv = oldenv;
X    xlfenv = oldfenv;
X
X    /* restore the stack */
X    xlpopn(3);
X
X    /* return the result value */
X    return (val);
X}
X
X/* xlclose - create a function closure */
XLVAL xlclose(name,type,fargs,body,env,fenv)
X  LVAL name,type,fargs,body,env,fenv;
X{
X    LVAL closure,key,arg,def,svar,new,last;
X    char keyname[STRMAX+2];
X
X    /* protect some pointers */
X    xlsave1(closure);
X
X    /* create the closure object */
X    closure = newclosure(name,type,env,fenv);
X    setlambda(closure,fargs);
X    setbody(closure,body);
X
X    /* handle each required argument */
X    last = NIL;
X    while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) {
X
X	/* make sure the argument is a symbol */
X	if (!symbolp(arg))
X	    badarglist();
X
X	/* create a new argument list entry */
X	new = cons(arg,NIL);
X
X	/* link it into the required argument list */
X	if (last)
X	    rplacd(last,new);
X	else
X	    setargs(closure,new);
X	last = new;
X
X	/* move the formal argument list pointer ahead */
X	fargs = cdr(fargs);
X    }
X
X    /* check for the '&optional' keyword */
X    if (consp(fargs) && car(fargs) == lk_optional) {
X	fargs = cdr(fargs);
X
X	/* handle each optional argument */
X	last = NIL;
X	while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) {
X
X	    /* get the default expression and specified-p variable */
X	    def = svar = NIL;
X	    if (consp(arg)) {
X		if (def = cdr(arg))
X		    if (consp(def)) {
X			if (svar = cdr(def))
X			    if (consp(svar)) {
X				svar = car(svar);
X				if (!symbolp(svar))
X				    badarglist();
X			    }
X			    else
X				badarglist();
X			def = car(def);
X		    }
X		    else
X			badarglist();
X		arg = car(arg);
X	    }
X
X	    /* make sure the argument is a symbol */
X	    if (!symbolp(arg))
X		badarglist();
X
X	    /* create a fully expanded optional expression */
X	    new = cons(cons(arg,cons(def,cons(svar,NIL))),NIL);
X
X	    /* link it into the optional argument list */
X	    if (last)
X		rplacd(last,new);
X	    else
X		setoargs(closure,new);
X	    last = new;
X		
X	    /* move the formal argument list pointer ahead */
X	    fargs = cdr(fargs);
X	}
X    }
X
X    /* check for the '&rest' keyword */
X    if (consp(fargs) && car(fargs) == lk_rest) {
X	fargs = cdr(fargs);
X
X	/* get the &rest argument */
X	if (consp(fargs) && (arg = car(fargs)) && !iskey(arg) && symbolp(arg))
X	    setrest(closure,arg);
X	else
X	    badarglist();
X
X	/* move the formal argument list pointer ahead */
X	fargs = cdr(fargs);
X    }
X
X    /* check for the '&key' keyword */
X    if (consp(fargs) && car(fargs) == lk_key) {
X	fargs = cdr(fargs);
X
X 	/* handle each key argument */
X	last = NIL;
X	while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) {
X
X	    /* get the default expression and specified-p variable */
X	    def = svar = NIL;
X	    if (consp(arg)) {
X		if (def = cdr(arg))
X		    if (consp(def)) {
X			if (svar = cdr(def))
X			    if (consp(svar)) {
X				svar = car(svar);
X				if (!symbolp(svar))
X				    badarglist();
X			    }
X			    else
X				badarglist();
X			def = car(def);
X		    }
X		    else
X			badarglist();
X		arg = car(arg);
X	    }
X
X	    /* get the keyword and the variable */
X	    if (consp(arg)) {
X		key = car(arg);
X		if (!symbolp(key))
X		    badarglist();
X		if (arg = cdr(arg))
X		    if (consp(arg))
X			arg = car(arg);
X		    else
X			badarglist();
X	    }
X	    else if (symbolp(arg)) {
X		strcpy(keyname,":");
X		strcat(keyname,getstring(getpname(arg)));
X		key = xlenter(keyname);
X	    }
X
X	    /* make sure the argument is a symbol */
X	    if (!symbolp(arg))
X		badarglist();
X
X	    /* create a fully expanded key expression */
X	    new = cons(cons(key,cons(arg,cons(def,cons(svar,NIL)))),NIL);
X
X	    /* link it into the optional argument list */
X	    if (last)
X		rplacd(last,new);
X	    else
X		setkargs(closure,new);
X	    last = new;
X
X	    /* move the formal argument list pointer ahead */
X	    fargs = cdr(fargs);
X	}
X    }
X
X    /* check for the '&allow-other-keys' keyword */
X    if (consp(fargs) && car(fargs) == lk_allow_other_keys)
X	fargs = cdr(fargs);	/* this is the default anyway */
X
X    /* check for the '&aux' keyword */
X    if (consp(fargs) && car(fargs) == lk_aux) {
X	fargs = cdr(fargs);
X
X	/* handle each aux argument */
X	last = NIL;
X	while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) {
X
X	    /* get the initial value */
X	    def = NIL;
X	    if (consp(arg)) {
X		if (def = cdr(arg))
X		    if (consp(def))
X			def = car(def);
X		    else
X			badarglist();
X		arg = car(arg);
X	    }
X
X	    /* make sure the argument is a symbol */
X	    if (!symbolp(arg))
X		badarglist();
X
X	    /* create a fully expanded aux expression */
X	    new = cons(cons(arg,cons(def,NIL)),NIL);
X
X	    /* link it into the aux argument list */
X	    if (last)
X		rplacd(last,new);
X	    else
X		setaargs(closure,new);
X	    last = new;
X
X	    /* move the formal argument list pointer ahead */
X	    fargs = cdr(fargs);
X	}
X    }
X
X    /* make sure this is the end of the formal argument list */
X    if (fargs)
X	badarglist();
X
X    /* restore the stack */
X    xlpop();
X
X    /* return the new closure */
X    return (closure);
X}
X
X/* xlabind - bind the arguments for a function */
Xxlabind(fun,argc,argv)
X  LVAL fun; int argc; LVAL *argv;
X{
X    LVAL *kargv,fargs,key,arg,def,svar,p;
X    int rargc,kargc;
X    
X    /* protect some pointers */
X    xlsave1(def);
X
X    /* bind each required argument */
X    for (fargs = getargs(fun); fargs; fargs = cdr(fargs)) {
X
X	/* make sure there is an actual argument */
X	if (--argc < 0)
X	    xlfail("too few arguments");
X
X	/* bind the formal variable to the argument value */
X	xlbind(car(fargs),*argv++);
X    }
X
X    /* bind each optional argument */
X    for (fargs = getoargs(fun); fargs; fargs = cdr(fargs)) {
X
X	/* get argument, default and specified-p variable */
X	p = car(fargs);
X	arg = car(p); p = cdr(p);
X	def = car(p); p = cdr(p);
X	svar = car(p);
X
X	/* bind the formal variable to the argument value */
X	if (--argc >= 0) {
X	    xlbind(arg,*argv++);
X	    if (svar) xlbind(svar,true);
X	}
X
X	/* bind the formal variable to the default value */
X	else {
X	    if (def) def = xleval(def);
X	    xlbind(arg,def);
X	    if (svar) xlbind(svar,NIL);
X	}
X    }
X
X    /* save the count of the &rest of the argument list */
X    rargc = argc;
X    
X    /* handle '&rest' argument */
X    if (arg = getrest(fun)) {
X	def = makearglist(argc,argv);
X	xlbind(arg,def);
X	argc = 0;
X    }
X
X    /* handle '&key' arguments */
X    if (fargs = getkargs(fun)) {
X	for (; fargs; fargs = cdr(fargs)) {
X
X	    /* get keyword, argument, default and specified-p variable */
X	    p = car(fargs);
X	    key = car(p); p = cdr(p);
X	    arg = car(p); p = cdr(p);
X	    def = car(p); p = cdr(p);
X	    svar = car(p);
X
X	    /* look for the keyword in the actual argument list */
X	    for (kargv = argv, kargc = rargc; (kargc -= 2) >= 0; kargv += 2)
X		if (*kargv == key)
X		    break;
X
X	    /* bind the formal variable to the argument value */
X	    if (kargc >= 0) {
X		xlbind(arg,*++kargv);
X		if (svar) xlbind(svar,true);
X	    }
X
X	    /* bind the formal variable to the default value */
X	    else {
X		if (def) def = xleval(def);
X		xlbind(arg,def);
X		if (svar) xlbind(svar,NIL);
X	    }
X	}
X	argc = 0;
X    }
X
X    /* check for the '&aux' keyword */
X    for (fargs = getaargs(fun); fargs; fargs = cdr(fargs)) {
X
X	/* get argument and default */
X	p = car(fargs);
X	arg = car(p); p = cdr(p);
X	def = car(p);
X
X	/* bind the auxiliary variable to the initial value */
X	if (def) def = xleval(def);
X	xlbind(arg,def);
X    }
X
X    /* make sure there aren't too many arguments */
X    if (argc > 0)
X	xlfail("too many arguments");
X
X    /* restore the stack */
X    xlpop();
X}
X
X/* doenter - print trace information on function entry */
XLOCAL doenter(sym,argc,argv)
X  LVAL sym; int argc; LVAL *argv;
X{
X    extern int xltrcindent;
X    int i;
X    
X    /* indent to the current trace level */
X    for (i = 0; i < xltrcindent; ++i)
X	trcputstr(" ");
X    ++xltrcindent;
X
X    /* display the function call */
X    sprintf(buf,"Entering: %s, Argument list: (",getstring(getpname(sym)));
X    trcputstr(buf);
X    while (--argc >= 0) {
X	trcprin1(*argv++);
X	if (argc) trcputstr(" ");
X    }
X    trcputstr(")\n");
X}
X
X/* doexit - print trace information for function/macro exit */
XLOCAL doexit(sym,val)
X  LVAL sym,val;
X{
X    extern int xltrcindent;
X    int i;
X    
X    /* indent to the current trace level */
X    --xltrcindent;
X    for (i = 0; i < xltrcindent; ++i)
X	trcputstr(" ");
X    
X    /* display the function value */
X    sprintf(buf,"Exiting: %s, Value: ",getstring(getpname(sym)));
X    trcputstr(buf);
X    trcprin1(val);
X    trcputstr("\n");
X}
X
X/* member - is 'x' a member of 'list'? */
XLOCAL int member(x,list)
X  LVAL x,list;
X{
X    for (; consp(list); list = cdr(list))
X	if (x == car(list))
X	    return (TRUE);
X    return (FALSE);
X}
X
X/* xlunbound - signal an unbound variable error */
Xxlunbound(sym)
X  LVAL sym;
X{
X    xlcerror("try evaluating symbol again","unbound variable",sym);
X}
X
X/* xlfunbound - signal an unbound function error */
Xxlfunbound(sym)
X  LVAL sym;
X{
X    xlcerror("try evaluating symbol again","unbound function",sym);
X}
X
X/* xlstkoverflow - signal a stack overflow error */
Xxlstkoverflow()
X{
X    xlabort("evaluation stack overflow");
X}
X
X/* xlargstkoverflow - signal an argument stack overflow error */
Xxlargstkoverflow()
X{
X    xlabort("argument stack overflow");
X}
X
X/* badarglist - report a bad argument list error */
XLOCAL badarglist()
X{
X    xlfail("bad formal argument list");
X}
SHAR_EOF
if test 19240 -ne "`wc -c 'xleval.c'`"
then
	echo shar: error transmitting "'xleval.c'" '(should have been 19240 characters)'
fi
#	End of shell archive
exit 0
-- 
Gary Murphy                   uunet!mitel!sce!cognos!garym
                              (garym%cognos.uucp@uunet.uu.net)
(613) 738-1338 x5537          Cognos Inc. P.O. Box 9707 Ottawa K1G 3N3
"There are many things which do not concern the process" - Joan of Arc