home *** CD-ROM | disk | FTP | other *** search
- /* xlcont - xlisp special forms */
- /* Copyright (c) 1985, by David Michael Betz
- All Rights Reserved
- Permission is granted for unrestricted non-commercial use */
-
- #include "xlisp.h"
-
- /* external variables */
- extern NODE *xlenv,*xlvalue;
- extern NODE *s_car,*s_cdr,*s_nth,*s_get,*s_svalue,*s_splist,*s_aref;
- extern NODE *s_lambda,*s_macro;
- extern NODE *s_comma,*s_comat;
- extern NODE *true;
-
- /* forward declarations */
- FORWARD NODE *bquote1();
- FORWARD NODE *defun();
- FORWARD NODE *let();
- FORWARD NODE *prog();
- FORWARD NODE *progx();
- FORWARD NODE *doloop();
-
- /* xquote - special form 'quote' */
- NODE *xquote(args)
- NODE *args;
- {
- if (atom(args))
- xlfail("too few arguments");
- else if (cdr(args) != NIL)
- xlfail("too many arguments");
- return (car(args));
- }
-
- /* xfunction - special form 'function' */
- NODE *xfunction(args)
- NODE *args;
- {
- NODE *val;
-
- /* get the argument */
- val = xlarg(&args);
- xllastarg(args);
-
- /* create a closure for lambda expressions */
- if (consp(val) && car(val) == s_lambda)
- val = cons(val,xlenv);
-
- /* otherwise, get the value of a symbol */
- else if (symbolp(val))
- val = xlgetvalue(val);
-
- /* otherwise, its an error */
- else
- xlerror("not a function",val);
-
- /* return the function */
- return (val);
- }
-
- /* xlambda - special form 'lambda' */
- NODE *xlambda(args)
- NODE *args;
- {
- NODE *fargs;
-
- /* get the formal argument list */
- fargs = xlmatch(LIST,&args);
-
- /* create a new function definition */
- return (cons(cons(s_lambda,cons(fargs,args)),xlenv));
- }
-
- /* xbquote - back quote special form */
- NODE *xbquote(args)
- NODE *args;
- {
- NODE *expr;
-
- /* get the expression */
- expr = xlarg(&args);
- xllastarg(args);
-
- /* fill in the template */
- return (bquote1(expr));
- }
-
- /* bquote1 - back quote helper function */
- LOCAL NODE *bquote1(expr)
- NODE *expr;
- {
- NODE ***oldstk,*val,*list,*last,*new;
-
- /* handle atoms */
- if (atom(expr))
- val = expr;
-
- /* handle (comma <expr>) */
- else if (car(expr) == s_comma) {
- if (atom(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) {
- oldstk = xlstack;
- xlstkcheck(2);
- xlsave(list);
- xlsave(val);
- if (atom(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));
- xlstack = oldstk;
- }
-
- /* handle any other list */
- else {
- oldstk = xlstack;
- xlsave1(val);
- val = consa(NIL);
- rplaca(val,bquote1(car(expr)));
- rplacd(val,bquote1(cdr(expr)));
- xlstack = oldstk;
- }
-
- /* return the result */
- return (val);
- }
-
- /* xsetq - special form 'setq' */
- NODE *xsetq(args)
- NODE *args;
- {
- NODE *sym,*val;
-
- /* handle each pair of arguments */
- for (val = NIL; args; ) {
- sym = xlmatch(SYM,&args);
- val = xlevarg(&args);
- xlsetvalue(sym,val);
- }
-
- /* return the result value */
- return (val);
- }
-
- /* xsetf - special form 'setf' */
- NODE *xsetf(args)
- NODE *args;
- {
- NODE ***oldstk,*place,*value;
-
- /* create a new stack frame */
- oldstk = xlstack;
- xlsave1(value);
-
- /* handle each pair of arguments */
- while (args) {
-
- /* get place and value */
- place = xlarg(&args);
- value = xlevarg(&args);
-
- /* check the place form */
- if (symbolp(place))
- xlsetvalue(place,value);
- else if (consp(place))
- placeform(place,value);
- else
- xlfail("bad place form");
- }
-
- /* restore the previous stack frame */
- xlstack = oldstk;
-
- /* return the value */
- return (value);
- }
-
- /* placeform - handle a place form other than a symbol */
- LOCAL placeform(place,value)
- NODE *place,*value;
- {
- NODE ***oldstk,*fun,*arg1,*arg2;
- int i;
-
- /* check the function name */
- if ((fun = xlmatch(SYM,&place)) == s_get) {
- oldstk = xlstack;
- xlstkcheck(2);
- xlsave(arg1);
- xlsave(arg2);
- arg1 = xlevmatch(SYM,&place);
- arg2 = xlevmatch(SYM,&place);
- xllastarg(place);
- xlputprop(arg1,value,arg2);
- xlstack = oldstk;
- }
- else if (fun == s_svalue) {
- oldstk = xlstack;
- xlsave1(arg1);
- arg1 = xlevmatch(SYM,&place);
- xllastarg(place);
- setvalue(arg1,value);
- xlstack = oldstk;
- }
- else if (fun == s_splist) {
- oldstk = xlstack;
- xlsave1(arg1);
- arg1 = xlevmatch(SYM,&place);
- xllastarg(place);
- setplist(arg1,value);
- xlstack = oldstk;
- }
- else if (fun == s_car) {
- oldstk = xlstack;
- xlsave1(arg1);
- if ((arg1 = xlevmatch(LIST,&place)) == NIL)
- xlerror("bad argument type",arg1);
- xllastarg(place);
- rplaca(arg1,value);
- xlstack = oldstk;
- }
- else if (fun == s_cdr) {
- oldstk = xlstack;
- xlsave1(arg1);
- if ((arg1 = xlevmatch(LIST,&place)) == NIL)
- xlerror("bad argument type",arg1);
- xllastarg(place);
- rplacd(arg1,value);
- xlstack = oldstk;
- }
- else if (fun == s_nth) {
- oldstk = xlstack;
- xlstkcheck(2);
- xlsave(arg1);
- xlsave(arg2);
- arg1 = xlevmatch(INT,&place);
- arg2 = xlevmatch(LIST,&place);
- xllastarg(place);
- for (i = (int)getfixnum(arg1); i > 0 && consp(arg2); --i)
- arg2 = cdr(arg2);
- if (consp(arg2))
- rplaca(arg2,value);
- xlstack = oldstk;
- }
-
- else if (fun == s_aref) {
- oldstk = xlstack;
- xlstkcheck(2);
- xlsave(arg1);
- xlsave(arg2);
- arg1 = xlevmatch(VECT,&place);
- arg2 = xlevmatch(INT,&place); i = (int)getfixnum(arg2);
- xllastarg(place);
- if (i < 0 || i >= getsize(arg1))
- xlerror("index out of range",arg2);
- setelement(arg1,i,value);
- xlstack = oldstk;
- }
- else
- xlfail("bad place form");
- }
-
- /* xdefun - special form 'defun' */
- NODE *xdefun(args)
- NODE *args;
- {
- return (defun(args,s_lambda));
- }
-
- /* xdefmacro - special form 'defmacro' */
- NODE *xdefmacro(args)
- NODE *args;
- {
- return (defun(args,s_macro));
- }
-
- /* defun - internal function definition routine */
- LOCAL NODE *defun(args,type)
- NODE *args,*type;
- {
- NODE *sym,*fargs;
-
- /* get the function symbol and formal argument list */
- sym = xlmatch(SYM,&args);
- fargs = xlmatch(LIST,&args);
-
- /* make the symbol point to a new function definition */
- xlsetvalue(sym,cons(cons(type,cons(fargs,args)),xlenv));
-
- /* return the function symbol */
- return (sym);
- }
-
- /* xcond - special form 'cond' */
- NODE *xcond(args)
- NODE *args;
- {
- NODE *list,*val;
-
- /* find a predicate that is true */
- for (val = NIL; consp(args); args = cdr(args)) {
-
- /* get the next conditional */
- list = car(args);
-
- /* 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);
- }
-
- /* xcase - special form 'case' */
- NODE *xcase(args)
- NODE *args;
- {
- NODE ***oldstk,*key,*list,*cases,*val;
-
- /* create a new stack frame */
- oldstk = xlstack;
- xlsave1(key);
-
- /* get the key expression */
- key = xlevarg(&args);
-
- /* find a case that matches */
- for (val = NIL; consp(args); args = cdr(args)) {
-
- /* get the next case clause */
- list = car(args);
-
- /* make sure this is a valid clause */
- if (consp(list)) {
-
- /* compare the key list against the key */
- if ((cases = car(list)) == 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 previous stack frame */
- xlstack = oldstk;
-
- /* return the value */
- return (val);
- }
-
- /* keypresent - check for the presence of a key in a list */
- LOCAL int keypresent(key,list)
- NODE *key,*list;
- {
- for (; consp(list); list = cdr(list))
- if (eql(car(list),key))
- return (TRUE);
- return (FALSE);
- }
-
- /* xand - special form 'and' */
- NODE *xand(args)
- NODE *args;
- {
- NODE *val;
-
- /* evaluate each argument */
- for (val = true; consp(args); args = cdr(args))
- if ((val = xleval(car(args))) == NIL)
- break;
-
- /* return the result value */
- return (val);
- }
-
- /* xor - special form 'or' */
- NODE *xor(args)
- NODE *args;
- {
- NODE *val;
-
- /* evaluate each argument */
- for (val = NIL; consp(args); args = cdr(args))
- if ((val = xleval(car(args))))
- break;
-
- /* return the result value */
- return (val);
- }
-
- /* xif - special form 'if' */
- NODE *xif(args)
- NODE *args;
- {
- NODE *testexpr,*thenexpr,*elseexpr;
-
- /* get the test expression, then clause and else clause */
- testexpr = xlarg(&args);
- thenexpr = xlarg(&args);
- elseexpr = (args ? xlarg(&args) : NIL);
- xllastarg(args);
-
- /* evaluate the appropriate clause */
- return (xleval(xleval(testexpr) ? thenexpr : elseexpr));
- }
-
- /* xlet - special form 'let' */
- NODE *xlet(args)
- NODE *args;
- {
- return (let(args,TRUE));
- }
-
- /* xletstar - special form 'let*' */
- NODE *xletstar(args)
- NODE *args;
- {
- return (let(args,FALSE));
- }
-
- /* let - common let routine */
- LOCAL NODE *let(args,pflag)
- NODE *args; int pflag;
- {
- NODE ***oldstk,*newenv,*val;
-
- /* create a new stack frame */
- oldstk = xlstack;
- xlsave1(newenv);
-
- /* create a new environment frame */
- newenv = xlframe(xlenv);
-
- /* get the list of bindings and bind the symbols */
- if (!pflag) xlenv = newenv;
- dobindings(xlmatch(LIST,&args),newenv);
- if (pflag) xlenv = newenv;
-
- /* execute the code */
- for (val = NIL; consp(args); args = cdr(args))
- val = xleval(car(args));
-
- /* unbind the arguments */
- xlenv = cdr(xlenv);
-
- /* restore the previous stack frame */
- xlstack = oldstk;
-
- /* return the result */
- return (val);
- }
-
- /* xprog - special form 'prog' */
- NODE *xprog(args)
- NODE *args;
- {
- return (prog(args,TRUE));
- }
-
- /* xprogstar - special form 'prog*' */
- NODE *xprogstar(args)
- NODE *args;
- {
- return (prog(args,FALSE));
- }
-
- /* prog - common prog routine */
- LOCAL NODE *prog(args,pflag)
- NODE *args; int pflag;
- {
- NODE ***oldstk,*newenv,*val;
-
- /* create a new stack frame */
- oldstk = xlstack;
- xlsave1(newenv);
-
- /* create a new environment frame */
- newenv = xlframe(xlenv);
-
- /* get the list of bindings and bind the symbols */
- if (!pflag) xlenv = newenv;
- dobindings(xlmatch(LIST,&args),newenv);
- if (pflag) xlenv = newenv;
-
- /* execute the code */
- tagblock(args,&val);
-
- /* unbind the arguments */
- xlenv = cdr(xlenv);
-
- /* restore the previous stack frame */
- xlstack = oldstk;
-
- /* return the result */
- return (val);
- }
-
- /* xgo - special form 'go' */
- NODE *xgo(args)
- NODE *args;
- {
- NODE *label;
-
- /* get the target label */
- label = xlarg(&args);
- xllastarg(args);
-
- /* transfer to the label */
- xlgo(label);
- }
-
- /* xreturn - special form 'return' */
- NODE *xreturn(args)
- NODE *args;
- {
- NODE *val;
-
- /* get the return value */
- val = (args ? xlevarg(&args) : NIL);
- xllastarg(args);
-
- /* return from the inner most block */
- xlreturn(val);
- }
-
- /* xprog1 - special form 'prog1' */
- NODE *xprog1(args)
- NODE *args;
- {
- return (progx(args,1));
- }
-
- /* xprog2 - special form 'prog2' */
- NODE *xprog2(args)
- NODE *args;
- {
- return (progx(args,2));
- }
-
- /* progx - common progx code */
- LOCAL NODE *progx(args,n)
- NODE *args; int n;
- {
- NODE ***oldstk,*val;
-
- /* create a new stack frame */
- oldstk = xlstack;
- xlsave1(val);
-
- /* evaluate the first n expressions */
- for (; consp(args) && --n >= 0; args = cdr(args))
- val = xleval(car(args));
-
- /* evaluate each remaining argument */
- for (; consp(args); args = cdr(args))
- xleval(car(args));
-
- /* restore the previous stack frame */
- xlstack = oldstk;
-
- /* return the last test expression value */
- return (val);
- }
-
- /* xprogn - special form 'progn' */
- NODE *xprogn(args)
- NODE *args;
- {
- NODE *val;
-
- /* evaluate each expression */
- for (val = NIL; consp(args); args = cdr(args))
- val = xleval(car(args));
-
- /* return the last test expression value */
- return (val);
- }
-
- /* xdo - special form 'do' */
- NODE *xdo(args)
- NODE *args;
- {
- return (doloop(args,TRUE));
- }
-
- /* xdostar - special form 'do*' */
- NODE *xdostar(args)
- NODE *args;
- {
- return (doloop(args,FALSE));
- }
-
- /* doloop - common do routine */
- LOCAL NODE *doloop(args,pflag)
- NODE *args; int pflag;
- {
- NODE ***oldstk,*newenv,*blist,*clist,*test,*rval;
- int rbreak;
-
- /* create a new stack frame */
- oldstk = xlstack;
- xlsave1(newenv);
-
- /* get the list of bindings, the exit test and the result forms */
- blist = xlmatch(LIST,&args);
- clist = xlmatch(LIST,&args);
- test = (consp(clist) ? car(clist) : NIL);
-
- /* create a new environment frame */
- newenv = xlframe(xlenv);
-
- /* 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 (rbreak = FALSE; xleval(test) == NIL; doupdates(blist,pflag))
- if (tagblock(args,&rval)) {
- rbreak = TRUE;
- break;
- }
-
- /* evaluate the result expression */
- if (!rbreak && consp(clist))
- for (rval = NIL, clist = cdr(clist); consp(clist); clist = cdr(clist))
- rval = xleval(car(clist));
-
- /* unbind the arguments */
- xlenv = cdr(xlenv);
-
- /* restore the previous stack frame */
- xlstack = oldstk;
-
- /* return the result */
- return (rval);
- }
-
- /* xdolist - special form 'dolist' */
- NODE *xdolist(args)
- NODE *args;
- {
- NODE ***oldstk,*clist,*sym,*list,*rval;
- int rbreak;
-
- /* create a new stack frame */
- oldstk = xlstack;
- xlsave1(list);
-
- /* get the control list (sym list result-expr) */
- clist = xlmatch(LIST,&args);
- sym = xlmatch(SYM,&clist);
- list = xlevmatch(LIST,&clist);
-
- /* initialize the local environment */
- xlenv = xlframe(xlenv);
- xlbind(sym,NIL,xlenv);
-
- /* loop through the list */
- for (rbreak = FALSE; consp(list); list = cdr(list)) {
-
- /* bind the symbol to the next list element */
- xlsetvalue(sym,car(list));
-
- /* execute the loop body */
- if (tagblock(args,&rval)) {
- rbreak = TRUE;
- break;
- }
- }
-
- /* evaluate the result expression */
- if (!rbreak) {
- xlsetvalue(sym,NIL);
- rval = (consp(clist) ? xleval(car(clist)) : NIL);
- }
-
- /* unbind the arguments */
- xlenv = cdr(xlenv);
-
- /* restore the previous stack frame */
- xlstack = oldstk;
-
- /* return the result */
- return (rval);
- }
-
- /* xdotimes - special form 'dotimes' */
- NODE *xdotimes(args)
- NODE *args;
- {
- NODE *clist,*sym,*rval;
- int rbreak,cnt,i;
-
- /* get the control list (sym list result-expr) */
- clist = xlmatch(LIST,&args);
- sym = xlmatch(SYM,&clist);
- cnt = getfixnum(xlevmatch(INT,&clist));
-
- /* initialize the local environment */
- xlenv = xlframe(xlenv);
- xlbind(sym,NIL,xlenv);
-
- /* loop through for each value from zero to cnt-1 */
- for (rbreak = FALSE, i = 0; i < cnt; ++i) {
-
- /* bind the symbol to the next list element */
- xlsetvalue(sym,cvfixnum((FIXNUM)i));
-
- /* execute the loop body */
- if (tagblock(args,&rval)) {
- rbreak = TRUE;
- break;
- }
- }
-
- /* evaluate the result expression */
- if (!rbreak) {
- xlsetvalue(sym,cvfixnum((FIXNUM)cnt));
- rval = (consp(clist) ? xleval(car(clist)) : NIL);
- }
-
- /* unbind the arguments */
- xlenv = cdr(xlenv);
-
- /* return the result */
- return (rval);
- }
-
- /* xcatch - special form 'catch' */
- NODE *xcatch(args)
- NODE *args;
- {
- NODE ***oldstk,*tag,*val;
- CONTEXT cntxt;
-
- /* create a new stack frame */
- oldstk = xlstack;
- xlsave1(tag);
-
- /* get the tag */
- tag = xlevarg(&args);
-
- /* 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; consp(args); args = cdr(args))
- val = xleval(car(args));
- }
- xlend(&cntxt);
-
- /* restore the previous stack frame */
- xlstack = oldstk;
-
- /* return the result */
- return (val);
- }
-
- /* xthrow - special form 'throw' */
- NODE *xthrow(args)
- NODE *args;
- {
- NODE *tag,*val;
-
- /* get the tag and value */
- tag = xlevarg(&args);
- val = (args ? xlevarg(&args) : NIL);
- xllastarg(args);
-
- /* throw the tag */
- xlthrow(tag,val);
- }
-
- /* xerrset - special form 'errset' */
- NODE *xerrset(args)
- NODE *args;
- {
- NODE *expr,*flag,*val;
- CONTEXT cntxt;
-
- /* get the expression and the print flag */
- expr = xlarg(&args);
- flag = (args ? xlarg(&args) : true);
- xllastarg(args);
-
- /* 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);
- }
-
- /* dobindings - handle bindings for let/let*, prog/prog*, do/do* */
- LOCAL dobindings(list,env)
- NODE *list,*env;
- {
- NODE ***oldstk,*bnd,*sym,*val;
-
- /* create a new stack frame */
- oldstk = xlstack;
- 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 = xlmatch(SYM,&bnd);
- val = xlevarg(&bnd);
- }
- else
- xlfail("bad binding");
-
- /* bind the value to the symbol */
- xlbind(sym,val,env);
- }
-
- /* restore the previous stack frame */
- xlstack = oldstk;
- }
-
- /* doupdates - handle updates for do/do* */
- doupdates(list,pflag)
- NODE *list; int pflag;
- {
- NODE ***oldstk,*plist,*bnd,*sym,*val;
-
- /* create a new stack frame */
- oldstk = xlstack;
- 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 = xlmatch(SYM,&bnd);
- bnd = cdr(bnd);
- if (bnd) {
- val = xlevarg(&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 previous stack frame */
- xlstack = oldstk;
- }
-
- /* tagblock - execute code within a block and tagbody */
- int tagblock(code,pval)
- NODE *code,**pval;
- {
- CONTEXT cntxt;
- int type,sts;
-
- /* establish an execution context */
- xlbegin(&cntxt,CF_GO|CF_RETURN,code);
-
- /* check for a 'return' */
- if ((type = setjmp(cntxt.c_jmpbuf)) == CF_RETURN) {
- *pval = xlvalue;
- sts = TRUE;
- }
-
- /* otherwise, enter the body */
- else {
-
- /* check for a 'go' */
- if (type == CF_GO)
- code = xlvalue;
-
- /* evaluate each expression in the body */
- for (; consp(code); code = cdr(code))
- if (consp(car(code)))
- xleval(car(code));
-
- /* fell out the bottom of the loop */
- *pval = NIL;
- sts = FALSE;
- }
- xlend(&cntxt);
-
- /* return status */
- return (sts);
- }
-