/* xsfun1.c - xscheme built-in functions - part 1 */ /* Copyright (c) 1988, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ #include "xscheme.h" /* gensym variables */ static char gsprefix[STRMAX+1] = { 'G',0 }; /* gensym prefix string */ static int gsnumber = 1; /* gensym number */ /* external variables */ extern LVAL xlenv,xlval,default_object,true; extern LVAL s_unbound; /* external routines */ extern int eq(),eqv(),equal(); /* forward declarations */ FORWARD LVAL cxr(); FORWARD LVAL member(); FORWARD LVAL assoc(); FORWARD LVAL nth(); FORWARD LVAL eqtest(); /* xcons - construct a new list cell */ LVAL xcons() { LVAL carval,cdrval; /* get the two arguments */ carval = xlgetarg(); cdrval = xlgetarg(); xllastarg(); /* construct a new cons node */ return (cons(carval,cdrval)); } /* xcar - built-in function 'car' */ LVAL xcar() { LVAL list; list = xlgalist(); xllastarg(); return (list ? car(list) : NIL); } /* xicar - built-in function '%car' */ LVAL xicar() { LVAL cons; cons = xlgetarg(); xllastarg(); return (car(cons)); } /* xcdr - built-in function 'cdr' */ LVAL xcdr() { LVAL list; list = xlgalist(); xllastarg(); return (list ? cdr(list) : NIL); } /* xicdr - built-in function '%cdr' */ LVAL xicdr() { LVAL cons; cons = xlgetarg(); xllastarg(); return (cdr(cons)); } /* cxxr functions */ LVAL xcaar() { return (cxr("aa")); } LVAL xcadr() { return (cxr("da")); } LVAL xcdar() { return (cxr("ad")); } LVAL xcddr() { return (cxr("dd")); } /* cxxxr functions */ LVAL xcaaar() { return (cxr("aaa")); } LVAL xcaadr() { return (cxr("daa")); } LVAL xcadar() { return (cxr("ada")); } LVAL xcaddr() { return (cxr("dda")); } LVAL xcdaar() { return (cxr("aad")); } LVAL xcdadr() { return (cxr("dad")); } LVAL xcddar() { return (cxr("add")); } LVAL xcdddr() { return (cxr("ddd")); } /* cxxxxr functions */ LVAL xcaaaar() { return (cxr("aaaa")); } LVAL xcaaadr() { return (cxr("daaa")); } LVAL xcaadar() { return (cxr("adaa")); } LVAL xcaaddr() { return (cxr("ddaa")); } LVAL xcadaar() { return (cxr("aada")); } LVAL xcadadr() { return (cxr("dada")); } LVAL xcaddar() { return (cxr("adda")); } LVAL xcadddr() { return (cxr("ddda")); } LVAL xcdaaar() { return (cxr("aaad")); } LVAL xcdaadr() { return (cxr("daad")); } LVAL xcdadar() { return (cxr("adad")); } LVAL xcdaddr() { return (cxr("ddad")); } LVAL xcddaar() { return (cxr("aadd")); } LVAL xcddadr() { return (cxr("dadd")); } LVAL xcdddar() { return (cxr("addd")); } LVAL xcddddr() { return (cxr("dddd")); } /* cxr - common car/cdr routine */ LOCAL LVAL cxr(adstr) char *adstr; { LVAL list; /* get the list */ list = xlgalist(); xllastarg(); /* perform the car/cdr operations */ while (*adstr && consp(list)) list = (*adstr++ == 'a' ? car(list) : cdr(list)); /* make sure the operation succeeded */ if (*adstr && list) xlbadtype(list); /* return the result */ return (list); } /* xsetcar - built-in function 'set-car!' */ LVAL xsetcar() { LVAL arg,newcar; /* get the cons and the new car */ arg = xlgacons(); newcar = xlgetarg(); xllastarg(); /* replace the car */ rplaca(arg,newcar); return (arg); } /* xisetcar - built-in function '%set-car!' */ LVAL xisetcar() { LVAL arg,newcar; /* get the cons and the new car */ arg = xlgetarg(); newcar = xlgetarg(); xllastarg(); /* replace the car */ rplaca(arg,newcar); return (arg); } /* xsetcdr - built-in function 'set-cdr!' */ LVAL xsetcdr() { LVAL arg,newcdr; /* get the cons and the new cdr */ arg = xlgacons(); newcdr = xlgetarg(); xllastarg(); /* replace the cdr */ rplacd(arg,newcdr); return (arg); } /* xisetcdr - built-in function '%set-cdr!' */ LVAL xisetcdr() { LVAL arg,newcdr; /* get the cons and the new cdr */ arg = xlgetarg(); newcdr = xlgetarg(); xllastarg(); /* replace the cdr */ rplacd(arg,newcdr); return (arg); } /* xlist - built-in function 'list' */ LVAL xlist() { LVAL last,next,val; /* initialize the list */ val = NIL; /* add each argument to the list */ if (moreargs()) { val = last = cons(nextarg(),NIL); while (moreargs()) { next = nextarg(); push(val); next = cons(next,NIL); rplacd(last,next); last = next; val = pop(); } } /* return the list */ return (val); } /* xappend - built-in function 'append' */ LVAL xappend() { LVAL next,this,last,val; /* append each argument */ for (val = last = NIL; xlargc > 1; ) /* append each element of this list to the result list */ for (next = xlgalist(); consp(next); next = cdr(next)) { push(val); this = cons(car(next),NIL); val = pop(); if (last == NIL) val = this; else rplacd(last,this); last = this; } /* tack on the last argument */ if (moreargs()) { if (last == NIL) val = xlgetarg(); else rplacd(last,xlgetarg()); } /* return the list */ return (val); } /* xreverse - built-in function 'reverse' */ LVAL xreverse() { LVAL next,val; /* get the list to reverse */ next = xlgalist(); xllastarg(); /* append each element of this list to the result list */ for (val = NIL; consp(next); next = cdr(next)) { push(val); val = cons(car(next),top()); drop(1); } /* return the list */ return (val); } /* xlastpair - built-in function 'last-pair' */ LVAL xlastpair() { LVAL list; /* get the list */ list = xlgalist(); xllastarg(); /* find the last cons */ if (consp(list)) while (consp(cdr(list))) list = cdr(list); /* return the last element */ return (list); } /* xlength - built-in function 'length' */ LVAL xlength() { FIXTYPE n; LVAL arg; /* get the argument */ arg = xlgalist(); xllastarg(); /* find the length */ for (n = (FIXTYPE)0; consp(arg); ++n) arg = cdr(arg); /* return the length */ return (cvfixnum(n)); } /* xmember - built-in function 'member' */ LVAL xmember() { return (member(equal)); } /* xmemv - built-in function 'memv' */ LVAL xmemv() { return (member(eqv)); } /* xmemq - built-in function 'memq' */ LVAL xmemq() { return (member(eq)); } /* member - common routine for member/memv/memq */ LOCAL LVAL member(fcn) int (*fcn)(); { LVAL x,list,val; /* get the expression to look for and the list */ x = xlgetarg(); list = xlgalist(); xllastarg(); /* look for the expression */ for (val = NIL; consp(list); list = cdr(list)) if ((*fcn)(x,car(list))) { val = list; break; } /* return the result */ return (val); } /* xassoc - built-in function 'assoc' */ LVAL xassoc() { return (assoc(equal)); } /* xassv - built-in function 'assv' */ LVAL xassv() { return (assoc(eqv)); } /* xassq - built-in function 'assq' */ LVAL xassq() { return (assoc(eq)); } /* assoc - common routine for assoc/assv/assq */ LOCAL LVAL assoc(fcn) int (*fcn)(); { LVAL x,alist,pair,val; /* get the expression to look for and the association list */ x = xlgetarg(); alist = xlgalist(); xllastarg(); /* look for the expression */ for (val = NIL; consp(alist); alist = cdr(alist)) if ((pair = car(alist)) && consp(pair)) if ((*fcn)(x,car(pair),fcn)) { val = pair; break; } /* return the result */ return (val); } /* xlistref - built-in function 'list-ref' */ LVAL xlistref() { return (nth(TRUE)); } /* xlisttail - built-in function 'list-tail' */ LVAL xlisttail() { return (nth(FALSE)); } /* nth - internal nth function */ LOCAL LVAL nth(carflag) int carflag; { LVAL list,arg; int n; /* get n and the list */ list = xlgalist(); arg = xlgafixnum(); xllastarg(); /* range check the index */ if ((n = (int)getfixnum(arg)) < 0) xlerror("index out of range",arg); /* find the nth element */ for (; consp(list) && n; n--) list = cdr(list); /* make sure the list was long enough */ if (n) xlerror("index out of range",arg); /* return the list beginning at the nth element */ return (carflag && consp(list) ? car(list) : list); } /* xboundp - is this a value bound to this symbol? */ LVAL xboundp() { LVAL sym; sym = xlgasymbol(); xllastarg(); return (boundp(sym) ? true : NIL); } /* xsymvalue - get the value of a symbol */ LVAL xsymvalue() { LVAL sym; sym = xlgasymbol(); xllastarg(); return (getvalue(sym)); } /* xsetsymvalue - set the value of a symbol */ LVAL xsetsymvalue() { LVAL sym,val; /* get the symbol */ sym = xlgasymbol(); val = xlgetarg(); xllastarg(); /* set the global value */ setvalue(sym,val); /* return its value */ return (val); } /* xsymplist - get the property list of a symbol */ LVAL xsymplist() { LVAL sym; /* get the symbol */ sym = xlgasymbol(); xllastarg(); /* return the property list */ return (getplist(sym)); } /* xsetsymplist - set the property list of a symbol */ LVAL xsetsymplist() { LVAL sym,val; /* get the symbol */ sym = xlgasymbol(); val = xlgetarg(); xllastarg(); /* set the property list */ setplist(sym,val); return (val); } /* xget - get the value of a property */ LVAL xget() { LVAL sym,prp; /* get the symbol and property */ sym = xlgasymbol(); prp = xlgasymbol(); xllastarg(); /* retrieve the property value */ return (xlgetprop(sym,prp)); } /* xput - set the value of a property */ LVAL xput() { LVAL sym,val,prp; /* get the symbol and property */ sym = xlgasymbol(); prp = xlgasymbol(); val = xlgetarg(); xllastarg(); /* set the property value */ xlputprop(sym,val,prp); /* return the value */ return (val); } /* xtheenvironment - built-in function 'the-environment' */ LVAL xtheenvironment() { xllastarg(); return (xlenv); } /* xprocenvironment - built-in function 'procedure-environment' */ LVAL xprocenvironment() { LVAL arg; arg = xlgaclosure(); xllastarg(); return (getenv(arg)); } /* xenvp - built-in function 'environment?' */ LVAL xenvp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (envp(arg) ? true : NIL); } /* xenvbindings - built-in function 'environment-bindings' */ LVAL xenvbindings() { LVAL env,frame,names,val,this,last; int len,i; /* get the environment */ env = xlgetarg(); xllastarg(); /* check the argument type */ if (closurep(env)) env = getenv(env); else if (!envp(env)) xlbadtype(env); /* initialize */ frame = car(env); names = getelement(frame,0); len = getsize(frame); check(1); /* build a list of dotted pairs */ for (val = last = NIL, i = 1; i < len; ++i, names = cdr(names)) { push(val); this = cons(cons(car(names),getelement(frame,i)),NIL); val = pop(); if (last) rplacd(last,this); else val = this; last = this; } return (val); } /* xenvparent - built-in function 'environment-parent' */ LVAL xenvparent() { LVAL env; env = xlgaenv(); xllastarg(); return (cdr(env)); } /* xvector - built-in function 'vector' */ LVAL xvector() { LVAL vect,*p; vect = newvector(xlargc); for (p = &vect->n_vdata[0]; moreargs(); ) *p++ = xlgetarg(); return (vect); } /* xmakevector - built-in function 'make-vector' */ LVAL xmakevector() { LVAL arg,val,*p; int len; /* get the vector size */ arg = xlgafixnum(); len = (int)getfixnum(arg); /* check for an initialization value */ if (moreargs()) { arg = xlgetarg(); /* get the initializer */ xllastarg(); /* make sure that's the last argument */ cpush(arg); /* save the initializer */ val = newvector(len); /* create the vector */ p = &val->n_vdata[0]; /* initialize the vector */ for (arg = pop(); --len >= 0; ) *p++ = arg; } /* no initialization value */ else val = newvector(len); /* defaults to initializing to NIL */ /* return the new vector */ return (val); } /* xvlength - built-in function 'vector-length' */ LVAL xvlength() { LVAL arg; arg = xlgavector(); xllastarg(); return (cvfixnum((FIXTYPE)getsize(arg))); } /* xivlength - built-in function '%vector-length' */ LVAL xivlength() { LVAL arg; arg = xlgetarg(); xllastarg(); return (cvfixnum((FIXTYPE)getsize(arg))); } /* xvref - built-in function 'vector-ref' */ LVAL xvref() { LVAL vref(); return (vref(xlgavector())); } /* xivref - built-in function '%vector-ref' */ LVAL xivref() { LVAL vref(); return (vref(xlgetarg())); } /* vref - common code for xvref and xivref */ LOCAL LVAL vref(vector) LVAL vector; { LVAL index; int i; /* get the index */ index = xlgafixnum(); xllastarg(); /* range check the index */ if ((i = (int)getfixnum(index)) < 0 || i >= getsize(vector)) xlerror("index out of range",index); /* return the vector element */ return (getelement(vector,i)); } /* xvset - built-in function 'vector-set!' */ LVAL xvset() { LVAL vset(); return (vset(xlgavector())); } /* xivset - built-in function '%vector-set!' */ LVAL xivset() { LVAL vset(); return (vset(xlgetarg())); } /* vset - common code for xvset and xivset */ LOCAL LVAL vset(vector) LVAL vector; { LVAL index,val; int i; /* get the index and the new value */ index = xlgafixnum(); val = xlgetarg(); xllastarg(); /* range check the index */ if ((i = (int)getfixnum(index)) < 0 || i >= getsize(vector)) xlerror("index out of range",index); /* set the vector element and return the value */ setelement(vector,i,val); return (val); } /* xvectlist - built-in function 'vector->list' */ LVAL xvectlist() { LVAL vect; int size; /* get the vector */ vect = xlgavector(); xllastarg(); /* make a list from the vector */ cpush(vect); size = getsize(vect); for (xlval = NIL; --size >= 0; ) xlval = cons(getelement(vect,size),xlval); drop(1); return (xlval); } /* xlistvect - built-in function 'list->vector' */ LVAL xlistvect() { LVAL vect,*p; int size; /* get the list */ xlval = xlgalist(); xllastarg(); /* make a vector from the list */ size = length(xlval); vect = newvector(size); for (p = &vect->n_vdata[0]; --size >= 0; xlval = cdr(xlval)) *p++ = car(xlval); return (vect); } /* xmakearray - built-in function 'make-array' */ LVAL xmakearray() { LVAL makearray1(),val; val = makearray1(xlargc,xlsp); drop(xlargc); return (val); } LVAL makearray1(argc,argv) int argc; LVAL *argv; { int size,i; LVAL arg; /* check for the end of the list of dimensions */ if (--argc < 0) return (NIL); /* get this dimension */ arg = *argv++; if (!fixp(arg)) xlbadtype(arg); size = (int)getfixnum(arg); /* make the new array */ cpush(newvector(size)); /* fill the array and return it */ for (i = 0; i < size; ++i) setelement(top(),i,makearray1(argc,argv)); return (pop()); } /* xaref - built-in function 'array-ref' */ LVAL xaref() { LVAL array,index; int i; /* get the array */ array = xlgavector(); /* get each array index */ while (xlargc > 1) { index = xlgafixnum(); i = (int)getfixnum(index); if (i < 0 || i > getsize(array)) xlerror("index out of range",index); array = getelement(array,i); if (!vectorp(array)) xlbadtype(array); } cpush(array); ++xlargc; return (xvref()); } /* xaset - built-in function 'array-set!' */ LVAL xaset() { LVAL array,index; int i; /* get the array */ array = xlgavector(); /* get each array index */ while (xlargc > 2) { index = xlgafixnum(); i = (int)getfixnum(index); if (i < 0 || i > getsize(array)) xlerror("index out of range",index); array = getelement(array,i); if (!vectorp(array)) xlbadtype(array); } cpush(array); ++xlargc; return (xvset()); } /* xnull - built-in function 'null?' */ LVAL xnull() { LVAL arg; arg = xlgetarg(); xllastarg(); return (null(arg) ? true : NIL); } /* xatom - built-in function 'atom?' */ LVAL xatom() { LVAL arg; arg = xlgetarg(); xllastarg(); return (atom(arg) ? true : NIL); } /* xlistp - built-in function 'list?' */ LVAL xlistp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (listp(arg) ? true : NIL); } /* xnumberp - built-in function 'number?' */ LVAL xnumberp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (numberp(arg) ? true : NIL); } /* xbooleanp - built-in function 'boolean?' */ LVAL xbooleanp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (arg == true || arg == NIL ? true : NIL); } /* xpairp - built-in function 'pair?' */ LVAL xpairp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (consp(arg) ? true : NIL); } /* xsymbolp - built-in function 'symbol?' */ LVAL xsymbolp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (symbolp(arg) ? true : NIL); } /* xintegerp - built-in function 'integer?' */ LVAL xintegerp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (fixp(arg) ? true : NIL); } /* xrealp - built-in function 'real?' */ LVAL xrealp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (floatp(arg) ? true : NIL); } /* xcharp - built-in function 'char?' */ LVAL xcharp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (charp(arg) ? true : NIL); } /* xstringp - built-in function 'string?' */ LVAL xstringp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (stringp(arg) ? true : NIL); } /* xvectorp - built-in function 'vector?' */ LVAL xvectorp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (vectorp(arg) ? true : NIL); } /* xprocedurep - built-in function 'procedure?' */ LVAL xprocedurep() { LVAL arg; arg = xlgetarg(); xllastarg(); return (closurep(arg) ? true : NIL); } /* xobjectp - built-in function 'object?' */ LVAL xobjectp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (closurep(arg) ? true : NIL); } /* xdefaultobjectp - built-in function 'default-object?' */ LVAL xdefaultobjectp() { LVAL arg; arg = xlgetarg(); xllastarg(); return (arg == default_object ? true : NIL); } /* xeq - built-in function 'eq?' */ LVAL xeq() { return (eqtest(eq)); } /* xeqv - built-in function 'eqv?' */ LVAL xeqv() { return (eqtest(eqv)); } /* xequal - built-in function 'equal?' */ LVAL xequal() { return (eqtest(equal)); } /* eqtest - common code for eq?/eqv?/equal? */ LOCAL LVAL eqtest(fcn) int (*fcn)(); { LVAL arg1,arg2; arg1 = xlgetarg(); arg2 = xlgetarg(); xllastarg(); return ((*fcn)(arg1,arg2) ? true : NIL); } /* xgensym - generate a symbol */ LVAL xgensym() { char sym[STRMAX+11]; /* enough space for prefix and number */ LVAL x; /* get the prefix or number */ if (moreargs()) { x = xlgetarg(); switch (ntype(x)) { case SYMBOL: x = getpname(x); case STRING: strncpy(gsprefix,getstring(x),STRMAX); gsprefix[STRMAX] = '\0'; break; case FIXNUM: gsnumber = getfixnum(x); break; default: xlerror("bad argument type",x); } } xllastarg(); /* create the pname of the new symbol */ sprintf(sym,"%s%d",gsprefix,gsnumber++); /* make a symbol with this print name */ return (cvsymbol(sym)); }