/* * * l i s t . c -- Lists procedures * * Copyright © 1993-1999 Erick Gallesio - I3S-CNRS/ESSI * * * Permission to use, copy, modify, distribute,and license this * software and its documentation for any purpose is hereby granted, * provided that existing copyright notices are retained in all * copies and that this notice is included verbatim in any * distributions. No written agreement, license, or royalty fee is * required for any of the authorized uses. * This software is provided ``AS IS'' without express or implied * warranty. * * * Author: Erick Gallesio [eg@kaolin.unice.fr] * Creation date: ??-Oct-1993 21:37 * Last file update: 3-Sep-1999 20:21 (eg) */ #include "stk.h" PRIMITIVE STk_pairp(SCM x) { return CONSP(x) ? Truth : Ntruth; } PRIMITIVE STk_cons(SCM x, SCM y) { SCM z; NEWCELL(z,tc_cons); CAR(z) = x; CDR(z) = y; return z; } PRIMITIVE STk_car(SCM x) { if (TYPEP(x, tc_cons)) return CAR(x); Err("car: wrong type of argument", x); return UNDEFINED; /* never reached */ } PRIMITIVE STk_cdr(SCM x) { if (TYPEP(x, tc_cons)) return CDR(x); Err("cdr: wrong type of argument", x); return UNDEFINED; /* never reached */ } PRIMITIVE STk_setcar(SCM cell, SCM value) { if NCONSP(cell) Err("set-car!: wrong type of argument", cell); CAR(cell) = value; return UNDEFINED; } PRIMITIVE STk_setcdr(SCM cell, SCM value) { if NCONSP(cell) Err("set-cdr!: wrong type of argument", cell); CDR(cell) = value; return UNDEFINED; } static SCM internal_cxr(SCM l, char *fct) { register SCM tmp = l; register char *p; for(p = fct + strlen(fct)-1; *p != 'X'; p--) { if (NCONSP(tmp)) { char name[50]; sprintf(name, "c%sr: bad list", fct+1); Err(name, l); } tmp = (*p == 'a') ? CAR(tmp) : CDR(tmp); } return tmp; } PRIMITIVE STk_caar (SCM l) { return internal_cxr(l, "Xaa"); } PRIMITIVE STk_cdar (SCM l) { return internal_cxr(l, "Xda"); } PRIMITIVE STk_cadr (SCM l) { return internal_cxr(l, "Xad"); } PRIMITIVE STk_cddr (SCM l) { return internal_cxr(l, "Xdd"); } PRIMITIVE STk_caaar (SCM l) { return internal_cxr(l, "Xaaa"); } PRIMITIVE STk_cdaar (SCM l) { return internal_cxr(l, "Xdaa"); } PRIMITIVE STk_cadar (SCM l) { return internal_cxr(l, "Xada"); } PRIMITIVE STk_cddar (SCM l) { return internal_cxr(l, "Xdda"); } PRIMITIVE STk_caadr (SCM l) { return internal_cxr(l, "Xaad"); } PRIMITIVE STk_cdadr (SCM l) { return internal_cxr(l, "Xdad"); } PRIMITIVE STk_caddr (SCM l) { return internal_cxr(l, "Xadd"); } PRIMITIVE STk_cdddr (SCM l) { return internal_cxr(l, "Xddd"); } PRIMITIVE STk_caaaar(SCM l) { return internal_cxr(l, "Xaaaa"); } PRIMITIVE STk_cdaaar(SCM l) { return internal_cxr(l, "Xdaaa"); } PRIMITIVE STk_cadaar(SCM l) { return internal_cxr(l, "Xadaa"); } PRIMITIVE STk_cddaar(SCM l) { return internal_cxr(l, "Xddaa"); } PRIMITIVE STk_caadar(SCM l) { return internal_cxr(l, "Xaada"); } PRIMITIVE STk_cdadar(SCM l) { return internal_cxr(l, "Xdada"); } PRIMITIVE STk_caddar(SCM l) { return internal_cxr(l, "Xadda"); } PRIMITIVE STk_cdddar(SCM l) { return internal_cxr(l, "Xddda"); } PRIMITIVE STk_caaadr(SCM l) { return internal_cxr(l, "Xaaad"); } PRIMITIVE STk_cdaadr(SCM l) { return internal_cxr(l, "Xdaad"); } PRIMITIVE STk_cadadr(SCM l) { return internal_cxr(l, "Xadad"); } PRIMITIVE STk_cddadr(SCM l) { return internal_cxr(l, "Xddad"); } PRIMITIVE STk_caaddr(SCM l) { return internal_cxr(l, "Xaadd"); } PRIMITIVE STk_cdaddr(SCM l) { return internal_cxr(l, "Xdadd"); } PRIMITIVE STk_cadddr(SCM l) { return internal_cxr(l, "Xaddd"); } PRIMITIVE STk_cddddr(SCM l) { return internal_cxr(l, "Xdddd"); } PRIMITIVE STk_nullp(SCM x) { return EQ(x, NIL) ? Truth: Ntruth; } int STk_llength(SCM l) { register SCM start = l; register int len = 0; for ( ; ; ) { if (NULLP(l)) return len; if ((l == start && len) || NCONSP(l)) return -1; l = CDR(l); len += 1; } } PRIMITIVE STk_listp(SCM x) { return (STk_llength(x) < 0) ? Ntruth : Truth; } PRIMITIVE STk_list(SCM l, int len) { /* len is unused here */ return l; } PRIMITIVE STk_list_length(SCM l) { int len = STk_llength(l); if (len >= 0) return STk_makeinteger((long) len); Err("length: not calculable.", NIL); return UNDEFINED; /* never reached */ } SCM STk_append2(SCM l1, SCM l2) { register SCM res, p; if (NULLP(l1)) return l2; if (NCONSP(l1)) goto Error; for (res = NIL; ; l1 = CDR(l1)) { if (NCONSP(l1)) goto Error; if (res == NIL){ NEWCELL(res, tc_cons); p = res; } else { NEWCELL(CDR(p), tc_cons); p = CDR(p); } CAR(p) = CAR(l1); CDR(p) = NIL; /* Keep always a valid list in case of a GC */ if (NCONSP(CDR(l1))) break; } CDR(p) = l2; return res; Error: Err("append: argument is not a list", l1); return UNDEFINED; /* never reached */ } PRIMITIVE STk_append(SCM l, int len) { switch (len) { case 0: return NIL; case 1: return CAR(l); case 2: return STk_append2(CAR(l), CAR(CDR(l))); default: return STk_append2(CAR(l), STk_append(CDR(l), len-1)); } } PRIMITIVE STk_reverse(SCM l) { SCM p, n = NIL; for(p=l; NNULLP(p); p=CDR(p)) { if (NCONSP(p)) Err("reverse: bad list", l); n = Cons(CAR(p),n); } return n; } PRIMITIVE STk_list_tail(SCM list, SCM k) { register long x; ENTER_PRIMITIVE("list-tail"); if (NCONSP(list) && NNULLP(list)) Serror("Bad list", list); x = STk_integer_value(k); if (x >= 0) { SCM l; for (l=list; x > 0; x--) { if (NULLP(l) || NCONSP(l)) Serror("list too short", list); l = CDR(l); } return l; } Serror("index must be exact positive integer", k); return UNDEFINED; /* never reached */ } PRIMITIVE STk_list_ref(SCM list, SCM k) { register long x; if (NCONSP(list)) Err("list-ref: Bad list", list); x = STk_integer_value(k); if (x >= 0) { SCM l = list; for ( ; x > 0; x--) { if (NULLP(l) || NCONSP(l)) goto Error; l = CDR(l); } if (CONSP(l)) return CAR(l); Error: Err("list-ref: list too short", list); } Err("list-ref: index must be exact positive integer", k); return UNDEFINED; /* never reached */ } static SCM lmember(SCM obj, SCM list, SCM (*predicate)(SCM, SCM) ) { register SCM ptr; if (NCONSP(list) && NNULLP(list)) goto Error; for (ptr=list; NNULLP(ptr); ) { if (CONSP(ptr)) { if ((*predicate)(CAR(ptr), obj) == Truth) return ptr; } else /* end of a dotted list */ return ((*predicate)(ptr, obj) == Truth) ? ptr : Ntruth; if ((ptr=CDR(ptr)) == list) Err("member: circular list", NIL); } return Ntruth; Error: Err("member: Bad list", list); return UNDEFINED; /* never reached */ } PRIMITIVE STk_memq (SCM obj, SCM list) {return lmember(obj, list, STk_eq); } PRIMITIVE STk_memv (SCM obj, SCM list) {return lmember(obj, list, STk_eqv); } PRIMITIVE STk_member(SCM obj, SCM list) {return lmember(obj, list, STk_equal);} static SCM lassoc(SCM obj, SCM alist, SCM (*predicate)(SCM, SCM)) { register SCM l,tmp; for(l=alist; CONSP(l); ) { tmp = CAR(l); if (CONSP(tmp) && (*predicate)(CAR(tmp), obj) == Truth) return tmp; if ((l=CDR(l)) == alist) goto Error; } if (NULLP(l)) return(Ntruth); Error: Err("assoc function: improper list", alist); return UNDEFINED; /* never reached */ } PRIMITIVE STk_assq (SCM obj, SCM alist){return lassoc(obj, alist, STk_eq); } PRIMITIVE STk_assv (SCM obj, SCM alist){return lassoc(obj, alist, STk_eqv); } PRIMITIVE STk_assoc(SCM obj, SCM alist){return lassoc(obj, alist, STk_equal);} /*** * * Non standard functions * ***/ PRIMITIVE STk_liststar(SCM l, int len) { if (len == 0) return NIL; /* l is a pair */ return (len == 1) ? CAR(l) : STk_cons(CAR(l), STk_liststar(CDR(l), len-1)); } PRIMITIVE STk_copy_tree(SCM l) { return CONSP(l) ? STk_cons(STk_copy_tree(CAR(l)), STk_copy_tree(CDR(l))): l; } PRIMITIVE STk_last_pair(SCM l) { register SCM tmp; ENTER_PRIMITIVE("last-pair"); if (NCONSP(l)) Serror("bad list", l); for (tmp=l; CONSP(CDR(l)); l = CDR(l)) /* Nothing */; return l; } /* * remove functions */ static SCM lremove(SCM obj, SCM list, SCM (*predicate)(SCM, SCM) ) { register SCM ptr, l; SCM result; if (NCONSP(list) && NNULLP(list)) goto Error; for (l=list, result=NIL; NNULLP(l); ) { if (NCONSP(l)) goto Error; if ((*predicate)(CAR(l), obj) == Ntruth) { if (NULLP(result)) { NEWCELL(result, tc_cons); ptr = result; } else { NEWCELL(CDR(ptr), tc_cons); ptr = CDR(ptr); } CAR(ptr) = CAR(l); CDR(ptr) = NIL; /* Keep always a valid list in case of a GC */ } if ((l=CDR(l)) == list) Err("remove: circular list", NIL); } return result; Error: Err("remove: Bad list", list); return UNDEFINED; /* never reached */ } PRIMITIVE STk_remq (SCM obj, SCM list) {return lremove(obj, list, STk_eq); } PRIMITIVE STk_remv (SCM obj, SCM list) {return lremove(obj, list, STk_eqv); } PRIMITIVE STk_remove(SCM obj, SCM list) {return lremove(obj, list, STk_equal);} /* * * destructive append (aka append!) * */ SCM STk_dappend2(SCM l1, SCM l2) { register SCM tmp; if (NULLP(l1)) return l2; for (tmp = l1; CONSP(tmp); tmp = CDR(tmp)) { if (NULLP(CDR(tmp))) { CDR(tmp) = l2; return l1; } } Err("append!: argument is not a list", tmp); return UNDEFINED; /* never reached */ } PRIMITIVE STk_dappend(SCM l, int len) { switch (len) { case 0: return NIL; case 1: return CAR(l); case 2: return STk_dappend2(CAR(l), CAR(CDR(l))); default: return STk_dappend2(CAR(l), STk_dappend(CDR(l), len-1)); } }