v10i091: XLisP 2.1 sources 2/5
Gary Murphy
garym at cognos.UUCP
Tue Feb 27 14:11:28 AEST 1990
Posting-number: Volume 10, Issue 91
Submitted-by: garym at 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 at 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
More information about the Comp.sources.misc
mailing list