diff options
Diffstat (limited to 'xlisp/xlcont.c')
-rw-r--r-- | xlisp/xlcont.c | 1428 |
1 files changed, 1428 insertions, 0 deletions
diff --git a/xlisp/xlcont.c b/xlisp/xlcont.c new file mode 100644 index 0000000..dc9d8cb --- /dev/null +++ b/xlisp/xlcont.c @@ -0,0 +1,1428 @@ +/* xlcont - xlisp special forms */ +/* Copyright (c) 1985, by David Michael Betz + All Rights Reserved + Permission is granted for unrestricted non-commercial use */ + +/* CHANGE LOG + * -------------------------------------------------------------------- + * 28Apr03 dm eliminate some compiler warnings + */ + + +#include "xlisp.h" + +/* external variables */ +extern LVAL xlvalue; +extern LVAL s_setf,s_car,s_cdr,s_nth,s_aref,s_get; +extern LVAL s_svalue,s_sfunction,s_splist; +extern LVAL s_lambda,s_macro; + +/* forward declarations */ +FORWARD LOCAL LVAL bquote1(LVAL expr); +FORWARD LOCAL void placeform(LVAL place, LVAL value); +FORWARD LOCAL LVAL let(int pflag); +FORWARD LOCAL LVAL flet(LVAL type, int letflag); +FORWARD LOCAL LVAL prog(int pflag); +FORWARD LOCAL LVAL progx(int n); +FORWARD LOCAL LVAL doloop(int pflag); +FORWARD LOCAL LVAL evarg(LVAL *pargs); +FORWARD LOCAL LVAL match(int type, LVAL *pargs); +FORWARD LOCAL LVAL evmatch(int type, LVAL *pargs); +FORWARD LOCAL void toofew(LVAL args); +FORWARD LOCAL void toomany(LVAL args); +FORWARD LOCAL void setffunction(LVAL fun, LVAL place, LVAL value); +FORWARD LOCAL int keypresent(LVAL key, LVAL list); +FORWARD LOCAL void dobindings(LVAL list, LVAL env); +FORWARD LOCAL void tagbody(void); +FORWARD LOCAL void doupdates(LVAL list, int pflag); + + +/* dummy node type for a list */ +#define LIST -1 + +/* xquote - special form 'quote' */ +LVAL xquote(void) +{ + LVAL val; + val = xlgetarg(); + xllastarg(); + return (val); +} + +/* xfunction - special form 'function' */ +LVAL xfunction(void) +{ + LVAL val; + + /* get the argument */ + val = xlgetarg(); + xllastarg(); + + /* create a closure for lambda expressions */ + if (consp(val) && car(val) == s_lambda && consp(cdr(val))) + val = xlclose(NIL,s_lambda,car(cdr(val)),cdr(cdr(val)),xlenv,xlfenv); + + /* otherwise, get the value of a symbol */ + else if (symbolp(val)) + val = xlgetfunction(val); + + /* otherwise, its an error */ + else + xlerror("not a function",val); + + /* return the function */ + return (val); +} + +/* xbquote - back quote special form */ +LVAL xbquote(void) +{ + LVAL expr; + + /* get the expression */ + expr = xlgetarg(); + xllastarg(); + + /* fill in the template */ + return (bquote1(expr)); +} + +/* bquote1 - back quote helper function */ +LOCAL LVAL bquote1(LVAL expr) +{ + LVAL val,list,last,new; + + /* handle atoms */ + if (atomp(expr)) + val = expr; + + /* handle (comma <expr>) */ + else if (car(expr) == s_comma) { + if (atomp(cdr(expr))) + xlfail("bad comma expression"); + val = xleval(car(cdr(expr))); + } + + /* handle ((comma-at <expr>) ... ) */ + else if (consp(car(expr)) && car(car(expr)) == s_comat) { + xlstkcheck(2); + xlsave(list); + xlsave(val); + if (atomp(cdr(car(expr)))) + xlfail("bad comma-at expression"); + list = xleval(car(cdr(car(expr)))); + for (last = NIL; consp(list); list = cdr(list)) { + new = consa(car(list)); + if (last) + rplacd(last,new); + else + val = new; + last = new; + } + if (last) + rplacd(last,bquote1(cdr(expr))); + else + val = bquote1(cdr(expr)); + xlpopn(2); + } + + /* handle any other list */ + else { + xlsave1(val); + val = consa(NIL); + rplaca(val,bquote1(car(expr))); + rplacd(val,bquote1(cdr(expr))); + xlpop(); + } + + /* return the result */ + return (val); +} + +/* xlambda - special form 'lambda' */ +LVAL xlambda(void) +{ + LVAL fargs,arglist,val; + + /* get the formal argument list and function body */ + xlsave1(arglist); + fargs = xlgalist(); + arglist = makearglist(xlargc,xlargv); + + /* create a new function definition */ + val = xlclose(NIL,s_lambda,fargs,arglist,xlenv,xlfenv); + + /* restore the stack and return the closure */ + xlpop(); + return (val); +} + +/* xgetlambda - get the lambda expression associated with a closure */ +LVAL xgetlambda(void) +{ + LVAL closure; + closure = xlgaclosure(); + return (cons(gettype(closure), + cons(getlambda(closure),getbody(closure)))); +} + +/* xsetq - special form 'setq' */ +LVAL xsetq(void) +{ + LVAL sym,val; + + /* handle each pair of arguments */ + for (val = NIL; moreargs(); ) { + sym = xlgasymbol(); + val = xleval(nextarg()); + xlsetvalue(sym,val); + } + + /* return the result value */ + return (val); +} + +/* xpsetq - special form 'psetq' */ +LVAL xpsetq(void) +{ + LVAL plist,sym,val; + + /* protect some pointers */ + xlsave1(plist); + + /* handle each pair of arguments */ + for (val = NIL; moreargs(); ) { + sym = xlgasymbol(); + val = xleval(nextarg()); + plist = cons(cons(sym,val),plist); + } + + /* do parallel sets */ + for (; plist; plist = cdr(plist)) + xlsetvalue(car(car(plist)),cdr(car(plist))); + + /* restore the stack */ + xlpop(); + + /* return the result value */ + return (val); +} + +/* xsetf - special form 'setf' */ +LVAL xsetf(void) +{ + LVAL place,value; + + /* protect some pointers */ + xlsave1(value); + + /* handle each pair of arguments */ + while (moreargs()) { + + /* get place and value */ + place = xlgetarg(); + value = xleval(nextarg()); + + /* expand macros in the place form */ + if (consp(place)) + place = xlexpandmacros(place); + + /* check the place form */ + if (symbolp(place)) + xlsetvalue(place,value); + else if (consp(place)) + placeform(place,value); + else + xlfail("bad place form"); + } + + /* restore the stack */ + xlpop(); + + /* return the value */ + return (value); +} + +/* placeform - handle a place form other than a symbol */ +LOCAL void placeform(LVAL place, LVAL value) +{ + LVAL fun,arg1,arg2; + int i; + + /* check the function name */ + if ((fun = match(SYMBOL,&place)) == s_get) { + xlstkcheck(2); + xlsave(arg1); + xlsave(arg2); + arg1 = evmatch(SYMBOL,&place); + arg2 = evmatch(SYMBOL,&place); + if (place) toomany(place); + xlputprop(arg1,value,arg2); + xlpopn(2); + } + else if (fun == s_svalue) { + arg1 = evmatch(SYMBOL,&place); + if (place) toomany(place); + setvalue(arg1,value); + } + else if (fun == s_sfunction) { + arg1 = evmatch(SYMBOL,&place); + if (place) toomany(place); + setfunction(arg1,value); + } + else if (fun == s_splist) { + arg1 = evmatch(SYMBOL,&place); + if (place) toomany(place); + setplist(arg1,value); + } + else if (fun == s_car) { + arg1 = evmatch(CONS,&place); + if (place) toomany(place); + rplaca(arg1,value); + } + else if (fun == s_cdr) { + arg1 = evmatch(CONS,&place); + if (place) toomany(place); + rplacd(arg1,value); + } + else if (fun == s_nth) { + xlsave1(arg1); + arg1 = evmatch(FIXNUM,&place); + arg2 = evmatch(LIST,&place); + if (place) toomany(place); + for (i = (int)getfixnum(arg1); i > 0 && consp(arg2); --i) + arg2 = cdr(arg2); + if (consp(arg2)) + rplaca(arg2,value); + xlpop(); + } + else if (fun == s_aref) { + xlsave1(arg1); + arg1 = evmatch(VECTOR,&place); + arg2 = evmatch(FIXNUM,&place); i = (int)getfixnum(arg2); + if (place) toomany(place); + if (i < 0 || i >= getsize(arg1)) + xlerror("index out of range",arg2); + setelement(arg1,i,value); + xlpop(); + } + else if ((fun = xlgetprop(fun,s_setf))) + setffunction(fun,place,value); + else + xlfail("bad place form"); +} + +/* setffunction - call a user defined setf function */ +LOCAL void setffunction(LVAL fun, LVAL place, LVAL value) +{ + LVAL *newfp; + int argc; + + /* create the new call frame */ + newfp = xlsp; + pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); + pusharg(fun); + pusharg(NIL); + + /* push the values of all of the place expressions and the new value */ + for (argc = 1; consp(place); place = cdr(place), ++argc) + pusharg(xleval(car(place))); + pusharg(value); + + /* insert the argument count and establish the call frame */ + newfp[2] = cvfixnum((FIXTYPE)argc); + xlfp = newfp; + + /* apply the function */ + xlapply(argc); +} + +/* xdefun - special form 'defun' */ +LVAL xdefun(void) +{ + LVAL sym,fargs,arglist; + + /* get the function symbol and formal argument list */ + xlsave1(arglist); + sym = xlgasymbol(); + fargs = xlgalist(); + arglist = makearglist(xlargc,xlargv); + + /* make the symbol point to a new function definition */ + xlsetfunction(sym,xlclose(sym,s_lambda,fargs,arglist,xlenv,xlfenv)); + + /* restore the stack and return the function symbol */ + xlpop(); + return (sym); +} + +/* xdefmacro - special form 'defmacro' */ +LVAL xdefmacro(void) +{ + LVAL sym,fargs,arglist; + + /* get the function symbol and formal argument list */ + xlsave1(arglist); + sym = xlgasymbol(); + fargs = xlgalist(); + arglist = makearglist(xlargc,xlargv); + + /* make the symbol point to a new function definition */ + xlsetfunction(sym,xlclose(sym,s_macro,fargs,arglist,NIL,NIL)); + + /* restore the stack and return the function symbol */ + xlpop(); + return (sym); +} + +/* xcond - special form 'cond' */ +LVAL xcond(void) +{ + LVAL list,val; + + /* find a predicate that is true */ + for (val = NIL; moreargs(); ) { + + /* get the next conditional */ + list = nextarg(); + + /* evaluate the predicate part */ + if (consp(list) && (val = xleval(car(list)))) { + + /* evaluate each expression */ + for (list = cdr(list); consp(list); list = cdr(list)) + val = xleval(car(list)); + + /* exit the loop */ + break; + } + } + + /* return the value */ + return (val); +} + +/* xwhen - special form 'when' */ +LVAL xwhen(void) +{ + LVAL val; + + /* check the test expression */ + if ((val = xleval(xlgetarg()))) + while (moreargs()) + val = xleval(nextarg()); + + /* return the value */ + return (val); +} + +/* xunless - special form 'unless' */ +LVAL xunless(void) +{ + LVAL val=NIL; + + /* check the test expression */ + if (xleval(xlgetarg()) == NIL) + while (moreargs()) + val = xleval(nextarg()); + + /* return the value */ + return (val); +} + +/* xcase - special form 'case' */ +LVAL xcase(void) +{ + LVAL key,list,cases,val; + + /* protect some pointers */ + xlsave1(key); + + /* get the key expression */ + key = xleval(nextarg()); + + /* find a case that matches */ + for (val = NIL; moreargs(); ) { + + /* get the next case clause */ + list = nextarg(); + + /* make sure this is a valid clause */ + if (consp(list)) { + + /* compare the key list against the key */ + if ((cases = car(list)) == s_true || + (listp(cases) && keypresent(key,cases)) || + eql(key,cases)) { + + /* evaluate each expression */ + for (list = cdr(list); consp(list); list = cdr(list)) + val = xleval(car(list)); + + /* exit the loop */ + break; + } + } + else + xlerror("bad case clause",list); + } + + /* restore the stack */ + xlpop(); + + /* return the value */ + return (val); +} + +/* keypresent - check for the presence of a key in a list */ +LOCAL int keypresent(LVAL key, LVAL list) +{ + for (; consp(list); list = cdr(list)) + if (eql(car(list),key)) + return (TRUE); + return (FALSE); +} + +/* xand - special form 'and' */ +LVAL xand(void) +{ + LVAL val; + + /* evaluate each argument */ + for (val = s_true; moreargs(); ) + if ((val = xleval(nextarg())) == NIL) + break; + + /* return the result value */ + return (val); +} + +/* x_or - special form 'or' */ +/* this was named xor, but that caused problems with c++ under gcc */ +LVAL x_or(void) +{ + LVAL val; + + /* evaluate each argument */ + for (val = NIL; moreargs(); ) + if ((val = xleval(nextarg()))) + break; + + /* return the result value */ + return (val); +} + +/* xif - special form 'if' */ +LVAL xif(void) +{ + LVAL testexpr,thenexpr,elseexpr; + + /* get the test expression, then clause and else clause */ + testexpr = xlgetarg(); + thenexpr = xlgetarg(); + elseexpr = (moreargs() ? xlgetarg() : NIL); + xllastarg(); + + /* evaluate the appropriate clause */ + return (xleval(xleval(testexpr) ? thenexpr : elseexpr)); +} + +/* xlet - special form 'let' */ +LVAL xlet(void) +{ + return (let(TRUE)); +} + +/* xletstar - special form 'let*' */ +LVAL xletstar(void) +{ + return (let(FALSE)); +} + +/* let - common let routine */ +LOCAL LVAL let(int pflag) +{ + LVAL newenv,val; + + /* protect some pointers */ + xlsave1(newenv); + + /* create a new environment frame */ + newenv = xlframe(xlenv); + + /* get the list of bindings and bind the symbols */ + if (!pflag) { + xlenv = newenv; + } + dobindings(xlgalist(),newenv); + if (pflag) { + xlenv = newenv; + } + + /* execute the code */ + for (val = NIL; moreargs(); ) + val = xleval(nextarg()); + + /* unbind the arguments */ + xlenv = cdr(xlenv); + + /* restore the stack */ + xlpop(); + + /* return the result */ + return (val); +} + +/* xflet - built-in function 'flet' */ +LVAL xflet(void) +{ + return (flet(s_lambda,TRUE)); +} + +/* xlabels - built-in function 'labels' */ +LVAL xlabels(void) +{ + return (flet(s_lambda,FALSE)); +} + +/* xmacrolet - built-in function 'macrolet' */ +LVAL xmacrolet(void) +{ + return (flet(s_macro,TRUE)); +} + +/* flet - common flet/labels/macrolet routine */ +LOCAL LVAL flet(LVAL type, int letflag) +{ + LVAL list,bnd,sym,fargs,val; + + /* create a new environment frame */ + xlfenv = xlframe(xlfenv); + + /* bind each symbol in the list of bindings */ + for (list = xlgalist(); consp(list); list = cdr(list)) { + + /* get the next binding */ + bnd = car(list); + + /* get the symbol and the function definition */ + sym = match(SYMBOL,&bnd); + fargs = match(LIST,&bnd); + val = xlclose(sym,type,fargs,bnd,xlenv,(letflag?cdr(xlfenv):xlfenv)); + + /* bind the value to the symbol */ + xlfbind(sym,val); + } + + /* execute the code */ + for (val = NIL; moreargs(); ) + val = xleval(nextarg()); + + /* unbind the arguments */ + xlfenv = cdr(xlfenv); + + /* return the result */ + return (val); +} + +/* xprog - special form 'prog' */ +LVAL xprog(void) +{ + return (prog(TRUE)); +} + +/* xprogstar - special form 'prog*' */ +LVAL xprogstar(void) +{ + return (prog(FALSE)); +} + +/* prog - common prog routine */ +LOCAL LVAL prog(int pflag) +{ + LVAL newenv,val; + XLCONTEXT cntxt; + + /* protect some pointers */ + xlsave1(newenv); + + /* create a new environment frame */ + newenv = xlframe(xlenv); + + /* establish a new execution context */ + xlbegin(&cntxt,CF_RETURN,NIL); + if (setjmp(cntxt.c_jmpbuf)) + val = xlvalue; + else { + + /* get the list of bindings and bind the symbols */ + if (!pflag) { + xlenv = newenv; + } + dobindings(xlgalist(),newenv); + if (pflag) { + xlenv = newenv; + } + + /* execute the code */ + tagbody(); + val = NIL; + + /* unbind the arguments */ + xlenv = cdr(xlenv); + } + xlend(&cntxt); + + /* restore the stack */ + xlpop(); + + /* return the result */ + return (val); +} + +/* 4035 is the "no return value" warning message */ +/* xgo, xreturn, xrtnfrom, and xthrow don't return anything */ +/* #pragma warning(disable: 4035) */ +/* xgo - special form 'go' */ +LVAL xgo(void) +{ + LVAL label; + + /* get the target label */ + label = xlgetarg(); + xllastarg(); + + /* transfer to the label */ + xlgo(label); + return NIL; /* never happens */ +} + +/* xreturn - special form 'return' */ +LVAL xreturn(void) +{ + LVAL val; + + /* get the return value */ + val = (moreargs() ? xleval(nextarg()) : NIL); + xllastarg(); + + /* return from the inner most block */ + xlreturn(NIL,val); + return NIL; /* never happens */ +} + +/* xrtnfrom - special form 'return-from' */ +LVAL xrtnfrom(void) +{ + LVAL name,val; + + /* get the return value */ + name = xlgasymbol(); + val = (moreargs() ? xleval(nextarg()) : NIL); + xllastarg(); + + /* return from the inner most block */ + xlreturn(name,val); + return NIL; /* never happens */ +} + +/* xprog1 - special form 'prog1' */ +LVAL xprog1(void) +{ + return (progx(1)); +} + +/* xprog2 - special form 'prog2' */ +LVAL xprog2(void) +{ + return (progx(2)); +} + +/* progx - common progx code */ +LOCAL LVAL progx(int n) +{ + LVAL val; + + /* protect some pointers */ + xlsave1(val); + + /* evaluate the first n expressions */ + while (moreargs() && --n >= 0) + val = xleval(nextarg()); + + /* evaluate each remaining argument */ + while (moreargs()) + xleval(nextarg()); + + /* restore the stack */ + xlpop(); + + /* return the last test expression value */ + return (val); +} + +/* xprogn - special form 'progn' */ +LVAL xprogn(void) +{ + LVAL val; + + /* evaluate each expression */ + for (val = NIL; moreargs(); ) + val = xleval(nextarg()); + + /* return the last test expression value */ + return (val); +} + +/* xprogv - special form 'progv' */ +LVAL xprogv(void) +{ + LVAL olddenv,vars,vals,val; + + /* protect some pointers */ + xlstkcheck(2); + xlsave(vars); + xlsave(vals); + + /* get the list of variables and the list of values */ + vars = xlgetarg(); vars = xleval(vars); + vals = xlgetarg(); vals = xleval(vals); + + /* bind the values to the variables */ + for (olddenv = xldenv; consp(vars); vars = cdr(vars)) { + if (!symbolp(car(vars))) + xlerror("expecting a symbol",car(vars)); + if (consp(vals)) { + xldbind(car(vars),car(vals)); + vals = cdr(vals); + } + else + xldbind(car(vars),s_unbound); + } + + /* evaluate each expression */ + for (val = NIL; moreargs(); ) + val = xleval(nextarg()); + + /* restore the previous environment and the stack */ + xlunbind(olddenv); + xlpopn(2); + + /* return the last test expression value */ + return (val); +} + +/* xloop - special form 'loop' */ +LVAL xloop(void) +{ + LVAL *argv,arg,val; + XLCONTEXT cntxt; + int argc; + + /* protect some pointers */ + xlsave1(arg); + + /* establish a new execution context */ + xlbegin(&cntxt,CF_RETURN,NIL); + if (setjmp(cntxt.c_jmpbuf)) + val = xlvalue; + else + for (argv = xlargv, argc = xlargc; ; xlargv = argv, xlargc = argc) + while (moreargs()) { + arg = nextarg(); + if (consp(arg)) + xleval(arg); + } + xlend(&cntxt); + + /* restore the stack */ + xlpop(); + + /* return the result */ + return (val); +} + +/* xdo - special form 'do' */ +LVAL xdo(void) +{ + return (doloop(TRUE)); +} + +/* xdostar - special form 'do*' */ +LVAL xdostar(void) +{ + return (doloop(FALSE)); +} + +/* doloop - common do routine */ +LOCAL LVAL doloop(int pflag) +{ + LVAL newenv,*argv,blist,clist,test,val; + XLCONTEXT cntxt; + int argc; + + /* protect some pointers */ + xlsave1(newenv); + + /* get the list of bindings, the exit test and the result forms */ + blist = xlgalist(); + clist = xlgalist(); + test = (consp(clist) ? car(clist) : NIL); + argv = xlargv; + argc = xlargc; + + /* create a new environment frame */ + newenv = xlframe(xlenv); + + /* establish a new execution context */ + xlbegin(&cntxt,CF_RETURN,NIL); + if (setjmp(cntxt.c_jmpbuf)) + val = xlvalue; + else { + + /* bind the symbols */ + if (!pflag) { + xlenv = newenv; + } + dobindings(blist,newenv); + if (pflag) { + xlenv = newenv; + } + + /* execute the loop as long as the test is false */ + for (val = NIL; xleval(test) == NIL; doupdates(blist,pflag)) { + xlargv = argv; + xlargc = argc; + tagbody(); + } + + /* evaluate the result expression */ + if (consp(clist)) + for (clist = cdr(clist); consp(clist); clist = cdr(clist)) + val = xleval(car(clist)); + + /* unbind the arguments */ + xlenv = cdr(xlenv); + } + xlend(&cntxt); + + /* restore the stack */ + xlpop(); + + /* return the result */ + return (val); +} + +/* xdolist - special form 'dolist' */ +LVAL xdolist(void) +{ + LVAL list,*argv,clist,sym,val; + XLCONTEXT cntxt; + int argc; + + /* protect some pointers */ + xlsave1(list); + + /* get the control list (sym list result-expr) */ + clist = xlgalist(); + sym = match(SYMBOL,&clist); + list = evmatch(LIST,&clist); + argv = xlargv; + argc = xlargc; + + /* initialize the local environment */ + xlenv = xlframe(xlenv); + xlbind(sym,NIL); + + /* establish a new execution context */ + xlbegin(&cntxt,CF_RETURN,NIL); + if (setjmp(cntxt.c_jmpbuf)) + val = xlvalue; + else { + + /* loop through the list */ + for (val = NIL; consp(list); list = cdr(list)) { + + /* bind the symbol to the next list element */ + xlsetvalue(sym,car(list)); + + /* execute the loop body */ + xlargv = argv; + xlargc = argc; + tagbody(); + } + + /* evaluate the result expression */ + xlsetvalue(sym,NIL); + val = (consp(clist) ? xleval(car(clist)) : NIL); + + /* unbind the arguments */ + xlenv = cdr(xlenv); + } + xlend(&cntxt); + + /* restore the stack */ + xlpop(); + + /* return the result */ + return (val); +} + +/* xdotimes - special form 'dotimes' */ +LVAL xdotimes(void) +{ + LVAL *argv,clist,sym,cnt,val; + XLCONTEXT cntxt; + int argc,n,i; + + /* get the control list (sym list result-expr) */ + clist = xlgalist(); + sym = match(SYMBOL,&clist); + cnt = evmatch(FIXNUM,&clist); n = getfixnum(cnt); + argv = xlargv; + argc = xlargc; + + /* establish a new execution context */ + xlbegin(&cntxt,CF_RETURN,NIL); + + /* initialize the local environment */ + xlenv = xlframe(xlenv); + xlbind(sym,NIL); + + if (setjmp(cntxt.c_jmpbuf)) + val = xlvalue; + else { + + /* loop through for each value from zero to n-1 */ + for (val = NIL, i = 0; i < n; ++i) { + + /* bind the symbol to the next list element */ + xlsetvalue(sym,cvfixnum((FIXTYPE)i)); + + /* execute the loop body */ + xlargv = argv; + xlargc = argc; + tagbody(); + } + + /* evaluate the result expression */ + xlsetvalue(sym,cnt); + val = (consp(clist) ? xleval(car(clist)) : NIL); + + /* unbind the arguments */ + xlenv = cdr(xlenv); + } + xlend(&cntxt); + + /* return the result */ + return (val); +} + +/* xblock - special form 'block' */ +LVAL xblock(void) +{ + LVAL name,val; + XLCONTEXT cntxt; + + /* get the block name */ + name = xlgetarg(); + if (name && !symbolp(name)) + xlbadtype(name); + + /* execute the block */ + xlbegin(&cntxt,CF_RETURN,name); + if (setjmp(cntxt.c_jmpbuf)) + val = xlvalue; + else + for (val = NIL; moreargs(); ) + val = xleval(nextarg()); + xlend(&cntxt); + + /* return the value of the last expression */ + return (val); +} + +/* xtagbody - special form 'tagbody' */ +LVAL xtagbody(void) +{ + tagbody(); + return (NIL); +} + +/* xcatch - special form 'catch' */ +LVAL xcatch(void) +{ + XLCONTEXT cntxt; + LVAL tag,val; + + /* protect some pointers */ + xlsave1(tag); + + /* get the tag */ + tag = xleval(nextarg()); + + /* establish an execution context */ + xlbegin(&cntxt,CF_THROW,tag); + + /* check for 'throw' */ + if (setjmp(cntxt.c_jmpbuf)) + val = xlvalue; + + /* otherwise, evaluate the remainder of the arguments */ + else { + for (val = NIL; moreargs(); ) + val = xleval(nextarg()); + } + xlend(&cntxt); + + /* restore the stack */ + xlpop(); + + /* return the result */ + return (val); +} + +/* xthrow - special form 'throw' */ +LVAL xthrow(void) +{ + LVAL tag,val; + + /* get the tag and value */ + tag = xleval(nextarg()); + val = (moreargs() ? xleval(nextarg()) : NIL); + xllastarg(); + + /* throw the tag */ + xlthrow(tag,val); + return NIL; /* never happens */ +} + +/* xunwindprotect - special form 'unwind-protect' */ +LVAL xunwindprotect(void) +{ + extern XLCONTEXT *xltarget; + extern int xlmask; + XLCONTEXT cntxt; + XLCONTEXT *target = NULL; + int mask = 0; + int sts; + LVAL val; + + /* protect some pointers */ + xlsave1(val); + + /* get the expression to protect */ + val = xlgetarg(); + + /* evaluate the protected expression */ + xlbegin(&cntxt,CF_UNWIND,NIL); + if ((sts = setjmp(cntxt.c_jmpbuf))) { + target = xltarget; + mask = xlmask; + val = xlvalue; + } + else + val = xleval(val); + xlend(&cntxt); + + /* evaluate the cleanup expressions */ + while (moreargs()) + xleval(nextarg()); + + /* if unwinding, continue unwinding */ + if (sts) + xljump(target,mask,val); + + /* restore the stack */ + xlpop(); + + /* return the value of the protected expression */ + return (val); +} + +/* xerrset - special form 'errset' */ +LVAL xerrset(void) +{ + LVAL expr,flag,val; + XLCONTEXT cntxt; + + /* get the expression and the print flag */ + expr = xlgetarg(); + flag = (moreargs() ? xlgetarg() : s_true); + xllastarg(); + + /* establish an execution context */ + xlbegin(&cntxt,CF_ERROR,flag); + + /* check for error */ + if (setjmp(cntxt.c_jmpbuf)) + val = NIL; + + /* otherwise, evaluate the expression */ + else { + expr = xleval(expr); + val = consa(expr); + } + xlend(&cntxt); + + /* return the result */ + return (val); +} + +/* xtrace - special form 'trace' */ +LVAL xtrace(void) +{ + LVAL sym,fun,this; + + /* loop through all of the arguments */ + sym = xlenter("*TRACELIST*"); + while (moreargs()) { + fun = xlgasymbol(); + + /* check for the function name already being in the list */ + for (this = getvalue(sym); consp(this); this = cdr(this)) + if (car(this) == fun) + break; + + /* add the function name to the list */ + if (null(this)) + setvalue(sym,cons(fun,getvalue(sym))); + } + return (getvalue(sym)); +} + +/* xuntrace - special form 'untrace' */ +LVAL xuntrace(void) +{ + LVAL sym,fun,this,last; + + /* loop through all of the arguments */ + sym = xlenter("*TRACELIST*"); + while (moreargs()) { + fun = xlgasymbol(); + + /* remove the function name from the list */ + last = NIL; + for (this = getvalue(sym); consp(this); this = cdr(this)) { + if (car(this) == fun) { + if (last) + rplacd(last,cdr(this)); + else + setvalue(sym,cdr(this)); + break; + } + last = this; + } + } + return (getvalue(sym)); +} + +/* dobindings - handle bindings for let/let*, prog/prog*, do/do* */ +LOCAL void dobindings(LVAL list, LVAL env) +{ + LVAL bnd, val; + LVAL sym = NULL; + + /* protect some pointers */ + xlsave1(val); + + /* bind each symbol in the list of bindings */ + for (; consp(list); list = cdr(list)) { + + /* get the next binding */ + bnd = car(list); + + /* handle a symbol */ + if (symbolp(bnd)) { + sym = bnd; + val = NIL; + } + + /* handle a list of the form (symbol expr) */ + else if (consp(bnd)) { + sym = match(SYMBOL,&bnd); + val = evarg(&bnd); + } + else + xlfail("bad binding"); + + /* bind the value to the symbol */ + xlpbind(sym,val,env); + } + + /* restore the stack */ + xlpop(); +} + +/* doupdates - handle updates for do/do* */ +LOCAL void doupdates(LVAL list, int pflag) +{ + LVAL plist,bnd,sym,val; + + /* protect some pointers */ + xlstkcheck(2); + xlsave(plist); + xlsave(val); + + /* bind each symbol in the list of bindings */ + for (; consp(list); list = cdr(list)) { + + /* get the next binding */ + bnd = car(list); + + /* handle a list of the form (symbol expr) */ + if (consp(bnd)) { + sym = match(SYMBOL,&bnd); + bnd = cdr(bnd); + if (bnd) { + val = evarg(&bnd); + if (pflag) + plist = cons(cons(sym,val),plist); + else + xlsetvalue(sym,val); + } + } + } + + /* set the values for parallel updates */ + for (; plist; plist = cdr(plist)) + xlsetvalue(car(car(plist)),cdr(car(plist))); + + /* restore the stack */ + xlpopn(2); +} + +/* tagbody - execute code within a block and tagbody */ +LOCAL void tagbody(void) +{ + LVAL *argv,arg; + XLCONTEXT cntxt; + int argc; + + /* establish an execution context */ + xlbegin(&cntxt,CF_GO,NIL); + argc = xlargc; + argv = xlargv; + + /* check for a 'go' */ + if (setjmp(cntxt.c_jmpbuf)) { + cntxt.c_xlargc = argc; + cntxt.c_xlargv = argv; + } + + /* execute the body */ + while (moreargs()) { + arg = nextarg(); + if (consp(arg)) + xleval(arg); + } + xlend(&cntxt); +} + +/* match - get an argument and match its type */ +LOCAL LVAL match(int type, LVAL *pargs) +{ + LVAL arg; + + /* make sure the argument exists */ + if (!consp(*pargs)) + toofew(*pargs); + + /* get the argument value */ + arg = car(*pargs); + + /* move the argument pointer ahead */ + *pargs = cdr(*pargs); + + /* check its type */ + if (type == LIST) { + if (arg && ntype(arg) != CONS) + xlerror("bad argument type",arg); + } + else { + if (arg == NIL || ntype(arg) != type) + xlerror("bad argument type",arg); + } + + /* return the argument */ + return (arg); +} + +/* evarg - get the next argument and evaluate it */ +LOCAL LVAL evarg(LVAL *pargs) +{ + LVAL arg; + + /* protect some pointers */ + xlsave1(arg); + + /* make sure the argument exists */ + if (!consp(*pargs)) + toofew(*pargs); + + /* get the argument value */ + arg = car(*pargs); + + /* move the argument pointer ahead */ + *pargs = cdr(*pargs); + + /* evaluate the argument */ + arg = xleval(arg); + + /* restore the stack */ + xlpop(); + + /* return the argument */ + return (arg); +} + +/* evmatch - get an evaluated argument and match its type */ +LOCAL LVAL evmatch(int type, LVAL *pargs) +{ + LVAL arg; + + /* protect some pointers */ + xlsave1(arg); + + /* make sure the argument exists */ + if (!consp(*pargs)) + toofew(*pargs); + + /* get the argument value */ + arg = car(*pargs); + + /* move the argument pointer ahead */ + *pargs = cdr(*pargs); + + /* evaluate the argument */ + arg = xleval(arg); + + /* check its type */ + if (type == LIST) { + if (arg && ntype(arg) != CONS) + xlerror("bad argument type",arg); + } + else { + if (arg == NIL || ntype(arg) != type) + xlerror("bad argument type",arg); + } + + /* restore the stack */ + xlpop(); + + /* return the argument */ + return (arg); +} + +/* toofew - too few arguments */ +LOCAL void toofew(LVAL args) +{ + xlerror("too few arguments",args); +} + +/* toomany - too many arguments */ +LOCAL void toomany(LVAL args) +{ + xlerror("too many arguments",args); +} + |