stk/Src/list.c

384 lines
9.5 KiB
C

/*
*
* l i s t . c -- Lists procedures
*
* Copyright © 1993-1999 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
*
*
* 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));
}
}