ref: a88cd71d79e142d686b01ff33624a4cc8febb268
dir: /subr.c/
#include "lisp.h"
int
floeq(flonum x, flonum y)
{
return fabs(x-y) < 0.000003;
}
typedef int (*Eql)(C *a, C *b);
int
eq(C *a, C *b)
{
return a == b;
}
int
equal(C *a, C *b)
{
tail:
if(atom(a) != atom(b))
return 0;
if(atom(a)){
if(fixnump(a))
return fixnump(b) &&
a->fix == b->fix;
if(flonump(a))
return flonump(b) &&
floeq(a->flo, b->flo);
if(stringp(a))
return stringp(b) &&
strcmp(a->str, b->str) == 0;
return a == b;
}
if(!equal(a->a, b->a))
return 0;
a = a->d;
b = b->d;
goto tail;
}
/* this is a bit ugly... */
int
getnumcase(C *lt, C *rt)
{
int type;
type = 0;
if(fixnump(lt))
{}
else if(flonump(lt))
type |= 1;
else
type |= ~0;
if(fixnump(rt))
{}
else if(flonump(rt))
type |= 2;
else
type |= ~0;
return type;
}
/* Types */
C *atom_subr(void){
return atom(alist[0]) ? t : nil;
}
C *fixp_subr(void){
return fixnump(alist[0]) ? t : nil;
}
C *floatp_subr(void){
return flonump(alist[0]) ? t : nil;
}
C *numberp_subr(void){
return numberp(alist[0]) ? t : nil;
}
C *stringp_subr(void){
return stringp(alist[0]) ? t : nil;
}
/* Basics */
C *eval_subr(void){
nargs = 0;
return eval(alist[0], alist[1]);
}
C *apply_subr(void){
nargs = 0;
return apply(alist[0], alist[1], alist[2]);
}
C *quote_fsubr(void){
if(alist[0] == nil)
err("error: arg count");
return alist[0]->a;
}
C *function_fsubr(void){
if(alist[0] == nil)
err("error: arg count");
return cons(funarg, cons(alist[0]->a, cons(alist[1], nil)));
}
C *comment_fsubr(void){
return noval;
}
C *prog2_lsubr(void){
if(largs.nargs < 2)
err("error: arg count");
return largs.alist[2];
}
C *progn_lsubr(void){
if(largs.nargs < 1)
err("error: arg count");
return largs.alist[largs.nargs];
}
C *arg_subr(void){
fixnum n;
if(!fixnump(alist[0]))
err("error: not a fixnum");
n = alist[0]->fix;
if(n < 1 || n > largs.nargs)
err("error: arg out of bounds");
return largs.alist[n];
}
/* List functions */
C *car(C *pair){
if(pair == nil)
return nil;
if(!listp(pair))
err("error: not a pair");
return pair->a;
}
C *cdr(C *pair){
if(pair == nil)
return nil;
if(!listp(pair))
err("error: not a pair");
return pair->d;
}
C *car_subr(void){ return car(alist[0]); }
C *cdr_subr(void){ return cdr(alist[0]); }
C *caar_subr(void){ return car(car(alist[0])); }
C *cadr_subr(void){ return car(cdr(alist[0])); }
C *cdar_subr(void){ return cdr(car(alist[0])); }
C *cddr_subr(void){ return cdr(cdr(alist[0])); }
C *caaar_subr(void){ return car(car(car(alist[0]))); }
C *caadr_subr(void){ return car(car(cdr(alist[0]))); }
C *cadar_subr(void){ return car(cdr(car(alist[0]))); }
C *caddr_subr(void){ return car(cdr(cdr(alist[0]))); }
C *cdaar_subr(void){ return cdr(car(car(alist[0]))); }
C *cdadr_subr(void){ return cdr(car(cdr(alist[0]))); }
C *cddar_subr(void){ return cdr(cdr(car(alist[0]))); }
C *cdddr_subr(void){ return cdr(cdr(cdr(alist[0]))); }
C *caaaar_subr(void){ return car(car(car(car(alist[0])))); }
C *caaadr_subr(void){ return car(car(car(cdr(alist[0])))); }
C *caadar_subr(void){ return car(car(cdr(car(alist[0])))); }
C *caaddr_subr(void){ return car(car(cdr(cdr(alist[0])))); }
C *cadaar_subr(void){ return car(cdr(car(car(alist[0])))); }
C *cadadr_subr(void){ return car(cdr(car(cdr(alist[0])))); }
C *caddar_subr(void){ return car(cdr(cdr(car(alist[0])))); }
C *cadddr_subr(void){ return car(cdr(cdr(cdr(alist[0])))); }
C *cdaaar_subr(void){ return cdr(car(car(car(alist[0])))); }
C *cdaadr_subr(void){ return cdr(car(car(cdr(alist[0])))); }
C *cdadar_subr(void){ return cdr(car(cdr(car(alist[0])))); }
C *cdaddr_subr(void){ return cdr(car(cdr(cdr(alist[0])))); }
C *cddaar_subr(void){ return cdr(cdr(car(car(alist[0])))); }
C *cddadr_subr(void){ return cdr(cdr(car(cdr(alist[0])))); }
C *cdddar_subr(void){ return cdr(cdr(cdr(car(alist[0])))); }
C *cddddr_subr(void){ return cdr(cdr(cdr(cdr(alist[0])))); }
C *eq_subr(void){
return alist[0] == alist[1] ? t : nil;
}
C *equal_subr(void){
return equal(alist[0], alist[1]) ? t : nil;
}
C *assoc_subr(void){
C *l;
if(!listp(alist[1]))
err("error: no list");
for(l = alist[1]; l != nil; l = l->d)
if(equal(l->a->a, alist[0]))
return l->a;
return nil;
}
C *assq_subr(void){
if(!listp(alist[1]))
err("error: no list");
return assq(alist[0], alist[1]);
}
C *sassoc_subr(void){
C *l;
l = assoc_subr();
return l != nil ? l : apply(alist[2], nil, nil);
}
C *sassq_subr(void){
C *l;
l = assq_subr();
return l != nil ? l : apply(alist[2], nil, nil);
}
C *last_subr(void){
C *l;
if(!listp(alist[0]))
err("error: no list");
for(l = alist[0]; l != nil; l = l->d)
if(atom(l->d))
return l;
return nil;
}
C *length_subr(void){
return mkfix(length(alist[0]));
}
C *member_aux(Eql cmp){
C *l;
for(l = alist[1]; l != nil; l = l->d){
if(atom(l))
err("error: no list");
if(cmp(l->a, alist[0]))
return t;
}
return nil;
}
C *member_subr(void){ return member_aux(equal); }
C *memq_subr(void){ return member_aux(eq); }
C *null_subr(void){
return alist[0] == nil ? t : nil;
}
/* Creating list structure */
C *cons_subr(void){
return cons(alist[0], alist[1]);
}
C *ncons_subr(void){
return cons(alist[0], nil);
}
C *xcons_subr(void){
return cons(alist[1], alist[0]);
}
C *list_fsubr(void){
return evlis(alist[0], alist[1]);
}
C *append_subr(void){
C *l, **p;
assert(temlis.a == nil);
p = (C**)&temlis.a;
for(l = alist[0]; l != nil; l = l->d){
if(atom(l))
err("error: no list");
*p = cons(l->a, nil);
p = &(*p)->d;
}
*p = alist[1];
l = temlis.a;
temlis.a = nil;
return l;
}
C *reverse_subr(void){
C *l;
assert(temlis.a == nil);
for(l = alist[0]; l != nil; l = l->d){
if(atom(l))
err("error: no list");
temlis.a = cons(l->a, temlis.a);
}
l = temlis.a;
temlis.a = nil;
return l;
}
/* Modifying list structure */
C *rplaca_subr(void){
if(atom(alist[0]))
err("error: atom");
alist[0]->a = alist[1];
return alist[0];
}
C *rplacd_subr(void){
if(atom(alist[0])) /* this could work on a symbolic atom */
err("error: atom");
alist[0]->d = alist[1];
return alist[0];
}
C *nconc_subr(void){
C *l;
for(l = alist[0]; l != nil; l = l->d){
if(atom(l))
err("error: no list");
if(l->d == nil){
l->d = alist[1];
break;
}
}
return alist[0];
}
C *nreverse_subr(void){
C *l, *n, *last;
last = nil;
for(l = alist[0]; l != nil; l = n){
if(atom(l))
err("error: no list");
n = l->d;
l->d = last;
last = l;
}
return last;
}
C *delete_aux(Eql cmp){
C **p;
fixnum n;
if(largs.nargs < 2)
err("error: arg count");
n = -1;
if(largs.nargs > 2)
n = largs.alist[3]->fix;
for(p = &largs.alist[2]; *p != nil; p = &(*p)->d){
if(atom(*p))
err("error: no list");
if(cmp((*p)->a, largs.alist[1])){
if(n-- == 0)
break;
*p = (*p)->d;
}
}
return largs.alist[2];
}
C *delete_lsubr(void){ return delete_aux(equal); }
C *delq_lsubr(void){ return delete_aux(eq); }
/* Boolean logic */
C *and_fsubr(void){
C *l;
int ret;
ret = 1;
for(l = alist[0]; l != nil; l = l->d)
if(eval(l->a, alist[1]) == nil){
ret = 0;
break;
}
return ret ? t : nil;
}
C *or_fsubr(void){
C *l;
int ret;
ret = 0;
for(l = alist[0]; l != nil; l = l->d)
if(eval(l->a, alist[1]) != nil){
ret = 1;
break;
}
return ret ? t : nil;
}
/* Symbols, values */
C *setq_fsubr(void){
C *tt, *a, *l, *last;
last = nil;
for(l = alist[0]; l != nil; l = l->d->d){
a = l->a;
if(a == nil || !symbolp(a))
err("error: need symbol");
last = eval(l->d->a, alist[1]);
tt = assq(a, alist[1]);
if(tt == nil)
putprop(a, last, value);
else
tt->d = last;
}
return last;
}
/* Has to be FSUBR here, also extended syntax */
C *set_fsubr(void){
C *tt, *a, *l, *last;
last = nil;
for(l = alist[0]; l != nil; l = l->d->d){
a = eval(l->a, alist[1]);
if(a == nil || !symbolp(a))
err("error: need symbol");
last = eval(l->d->a, alist[1]);
tt = assq(a, alist[1]);
if(tt == nil)
putprop(a, last, value);
else
tt->d = last;
}
return last;
}
C *boundp_subr(void){
if(alist[0] == nil || !symbolp(alist[0]))
err("error: need symbol");
return symeval(alist[0]) == unbound ? nil : t;
}
C *makunbound_subr(void){
if(alist[0] == nil || !symbolp(alist[0]))
err("error: need symbol");
putprop(alist[0], unbound, value);
return alist[0];
}
/* Property list */
C *get_subr(void){
return get(alist[0], alist[1]);
}
C *getl_subr(void){
C *pl, *l;
pl = alist[0];
if(pl == nil || !(listp(pl) || symbolp(pl)))
return nil;
for(pl = pl->d; pl != nil; pl = pl->d->d){
assert(listp(pl));
for(l = alist[1]; l != nil; l = l->d){
if(atom(l))
err("error: no list");
if(pl->a == l->a)
return pl;
}
}
return nil;
}
C *putprop_subr(void){
return putprop(alist[0], alist[1], alist[2]);
}
C *defprop_fsubr(void){
if(length(alist[0]) != 3)
err("error: arg count");
return putprop(alist[0]->a, alist[0]->d->a, alist[0]->d->d->a);
}
C *remprop_subr(void){
C *l, **p;
p = &alist[0]->d;
for(l = *p; l != nil; l = l->d){
if(l->a == alist[1]){
*p = l->d->d;
break;
}
p = &(*p)->d;
}
return nil;
}
C*
mkchar(char c)
{
char str[2];
str[0] = c;
str[1] = '\0';
return intern(str);
}
#define NEEDNAME(x) if(symbolp(x)) x = getpname(x); if(!stringp(x)) err("error: not a string")
/* pname/string functions */
C *samepnamep_subr(void){
NEEDNAME(alist[0]);
NEEDNAME(alist[1]);
return strcmp(alist[0]->str, alist[1]->str) == 0 ? t : nil;
}
C *alphalessp_subr(void){
NEEDNAME(alist[0]);
NEEDNAME(alist[1]);
return strcmp(alist[0]->str, alist[1]->str) < 0 ? t : nil;
}
C *getchar_subr(void){
NEEDNAME(alist[0]);
if(!fixnump(alist[1])) err("error: not a number");
if(alist[1]->fix < 1 || alist[1]->fix > strlen(alist[0]->str))
return nil;
return mkchar(alist[0]->str[alist[1]->fix-1]);
}
C *intern_subr(void){
C *c, *name;
name = alist[0];
NEEDNAME(name);
c = findsym(name->str);
if(c == nil){
if(symbolp(alist[0]))
c = alist[0];
else
c = mksym(name->str);
oblist = cons(c, oblist);
}
return c;
}
C *remob_subr(void){
C **c;
if(!symbolp(alist[0])) err("error: not a symbol");
for(c = &oblist; *c != nil; c = &(*c)->d){
if((*c)->a == alist[0]){
*c = (*c)->d;
break;
}
}
return nil;
}
C *gensym_lsubr(void){
static int num = 1;
static char chr = 'G';
char str[6];
if(largs.nargs == 1){
if(symbolp(largs.alist[1])) largs.alist[1] = getpname(largs.alist[1]);
if(stringp(largs.alist[1]))
chr = largs.alist[1]->str[0];
else if(fixnump(largs.alist[1]))
num = largs.alist[1]->fix;
else
err("error: not string or number");
}
str[0] = chr;
str[1] = '0' + ((num/1000)%10);
str[2] = '0' + ((num/100)%10);
str[3] = '0' + ((num/10)%10);
str[4] = '0' + (num%10);
num++;
return mksym(str);
}
/* Number predicates */
C *zerop_subr(void){
int res;
res = 0;
if(fixnump(alist[0]))
res = alist[0]->fix == 0;
else if(flonump(alist[0]))
res = floeq(alist[0]->flo, 0.0);
else
err("error: not a number");
return res ? t : nil;
}
C *plusp_subr(void){
int res;
res = 0;
if(fixnump(alist[0]))
res = alist[0]->fix > 0;
else if(flonump(alist[0]))
res = alist[0]->flo > 0.0;
else
err("error: not a number");
return res ? t : nil;
}
C *minusp_subr(void){
int res;
res = 0;
if(fixnump(alist[0]))
res = alist[0]->fix < 0;
else if(flonump(alist[0]))
res = alist[0]->flo < 0.0;
else
err("error: not a number");
return res ? t : nil;
}
C *greaterp_lsubr(void){
C *lt, *rt;
int i;
if(largs.nargs < 2)
err("error: arg count");
for(i = 1; i < largs.nargs; i++){
lt = largs.alist[i];
rt = largs.alist[i+1];
switch(getnumcase(lt, rt)){
case 0:
if(lt->fix <= rt->fix)
return nil;
break;
case 1:
if(lt->flo <= rt->fix)
return nil;
break;
case 2:
if(lt->fix <= rt->flo)
return nil;
break;
case 3:
if(lt->flo <= rt->flo)
return nil;
break;
default:
err("error: not a number");
return nil;
}
}
return t;
}
C *lessp_lsubr(void){
C *lt, *rt;
int i;
if(largs.nargs < 2)
err("error: arg count");
for(i = 1; i < largs.nargs; i++){
lt = largs.alist[i];
rt = largs.alist[i+1];
switch(getnumcase(lt, rt)){
case 0:
if(lt->fix >= rt->fix)
return nil;
break;
case 1:
if(lt->flo >= rt->fix)
return nil;
break;
case 2:
if(lt->fix >= rt->flo)
return nil;
break;
case 3:
if(lt->flo >= rt->flo)
return nil;
break;
default:
err("error: not a number");
return nil;
}
}
return t;
}
C *max_lsubr(void){
int i;
C *tt;
fixnum fix;
flonum flo;
int type;
fix = FIXMIN;
flo = -FLOMAX;
type = 0; // fix;
for(i = 1; i <= largs.nargs; i++){
tt = largs.alist[i];
if(fixnump(tt))
fix = tt->fix > fix ? tt->fix : fix;
else if(flonump(tt)){
flo = tt->flo > flo ? tt->flo : flo;
type = 1;
}else
err("error: not a number");
}
return type == 0 ? mkfix(fix) : mkflo(fix > flo ? fix : flo);
}
C *min_lsubr(void){
int i;
C *tt;
fixnum fix;
flonum flo;
int type;
fix = FIXMAX;
flo = FLOMAX;
type = 0; // fix;
for(i = 1; i <= largs.nargs; i++){
tt = largs.alist[i];
if(fixnump(tt))
fix = tt->fix < fix ? tt->fix : fix;
else if(flonump(tt)){
flo = tt->flo < flo ? tt->flo : flo;
type = 1;
}else
err("error: not a number");
}
return type == 0 ? mkfix(fix) : mkflo(fix < flo ? fix : flo);
}
/* Arithmetic */
C *plus_lsubr(void){
int i;
C *tt;
fixnum fix;
flonum flo;
int type;
fix = 0;
flo = 0.0;
type = 0; // fix;
for(i = 1; i <= largs.nargs; i++){
tt = largs.alist[i];
if(fixnump(tt))
fix += tt->fix;
else if(flonump(tt)){
flo += tt->flo;
type = 1;
}else
err("error: not a number");
}
return type == 0 ? mkfix(fix) : mkflo(fix+flo);
}
C *difference_lsubr(void){
int i;
C *tt;
fixnum fix;
flonum flo;
int type;
int first;
first = 1;
fix = 0;
flo = 0.0;
type = 0; // fix;
if(largs.nargs == 0)
err("error: not enough args");
for(i = 1; i <= largs.nargs; i++){
tt = largs.alist[i];
if(fixnump(tt))
fix += first ? tt->fix : -tt->fix;
else if(flonump(tt)){
flo += first ? tt->flo : -tt->flo;
type = 1;
}else
err("error: not a number");
first = 0;
}
if(largs.nargs == 1)
return type == 0 ? mkfix(-fix) : mkflo(-fix-flo);
return type == 0 ? mkfix(fix) : mkflo(fix+flo);
}
C *times_lsubr(void){
int i;
C *tt;
fixnum fix;
flonum flo;
int type;
fix = 1;
flo = 1.0;
type = 0; // fix;
for(i = 1; i <= largs.nargs; i++){
tt = largs.alist[i];
if(fixnump(tt))
fix *= tt->fix;
else if(flonump(tt)){
flo *= tt->flo;
type = 1;
}else
err("error: not a number");
}
return type == 0 ? mkfix(fix) : mkflo(fix*flo);
}
C *quotient_lsubr(void){
int i;
C *tt;
fixnum fix;
flonum flo;
int type;
fix = 1;
flo = 1.0;
type = 0; // fix;
if(largs.nargs == 0)
return mkfix(1);
for(i = 2; i <= largs.nargs; i++){
tt = largs.alist[i];
if(fixnump(tt))
fix *= tt->fix;
else if(flonump(tt)){
flo *= tt->flo;
type = 1;
}else
err("error: not a number");
}
tt = largs.alist[1];
if(largs.nargs == 1){
if(fixnump(tt))
return mkfix(1/tt->fix);
else if(flonump(tt))
return mkflo(1.0/tt->flo);
else
err("error: not a number");
}
if(fixnump(tt))
return type == 0 ? mkfix(tt->fix/fix) : mkflo(tt->fix/(fix*flo));
else if(flonump(tt))
return type == 0 ? mkflo(tt->flo/fix) : mkflo(tt->flo/(fix*flo));
else
err("error: not a number");
/* can't happen */
return nil;
}
C *add1_subr(void){
if(fixnump(alist[0]))
return mkfix(alist[0]->fix+1);
if(flonump(alist[0]))
return mkflo(alist[0]->flo+1.0);
err("error: not a number");
return nil;
}
C *sub1_subr(void){
if(fixnump(alist[0]))
return mkfix(alist[0]->fix-1);
if(flonump(alist[0]))
return mkflo(alist[0]->flo-1.0);
err("error: not a number");
return nil;
}
C *remainder_subr(void){
switch(getnumcase(alist[0], alist[1])){
case 0:
if(alist[1]->fix == 0)
err("error: division by zero");
return mkfix(alist[0]->fix % alist[1]->fix);
break;
case 1:
return mkflo(fmod(alist[0]->flo, alist[1]->fix));
break;
case 2:
return mkflo(fmod(alist[0]->fix, alist[1]->flo));
break;
case 3:
return mkflo(fmod(alist[0]->flo, alist[1]->flo));
break;
default:
err("error: not a number");
return nil;
}
}
C *expt_subr(void){
switch(getnumcase(alist[0], alist[1])){
case 0:
if(alist[1]->fix == 0)
err("error: division by zero");
return mkfix(pow(alist[0]->fix, alist[1]->fix));
break;
case 1:
return mkflo(exp(log(alist[0]->flo) * alist[1]->fix));
break;
case 2:
return mkflo(exp(log(alist[0]->fix) * alist[1]->flo));
break;
case 3:
return mkflo(exp(log(alist[0]->flo) * alist[1]->flo));
break;
default:
err("error: not a number");
return nil;
}
}
/* Bitwise operations */
C *logior_lsubr(void){
int i;
C *tt;
fixnum fix;
fix = 0;
for(i = 1; i <= largs.nargs; i++){
tt = largs.alist[i];
if(fixnump(tt))
fix |= tt->fix;
else
err("error: not a fixnum");
}
return mkfix(fix);
}
C *logand_lsubr(void){
int i;
C *tt;
fixnum fix;
fix = ~0;
for(i = 1; i <= largs.nargs; i++){
tt = largs.alist[i];
if(fixnump(tt))
fix &= tt->fix;
else
err("error: not a fixnum");
}
return mkfix(fix);
}
C *logxor_lsubr(void){
int i;
C *tt;
fixnum fix;
fix = 0;
for(i = 1; i <= largs.nargs; i++){
tt = largs.alist[i];
if(fixnump(tt))
fix ^= tt->fix;
else
err("error: not a fixnum");
}
return mkfix(fix);
}
C *lsh_subr(void){
if(!fixnump(alist[0]) || !fixnump(alist[1]))
err("error: not a fixnum");
if(alist[1]->fix < 0)
return mkfix((word)alist[0]->fix >> -alist[1]->fix);
else
return mkfix((word)alist[0]->fix << alist[1]->fix);
}
/* Character manipulation */
static C *mkfixchar(char c) { return mkfix(c); }
static C *str2list(char *str, C *(*f)(char)){
C **lp;
char *s;
lp = push(nil);
for(s = str; *s != '\0'; s++){
*lp = cons(f(*s), nil);
lp = &(*lp)->d;
}
return pop();
}
static Strbuf list2str(C *l){
Strbuf buf;
if(!listp(l)) err("error: not a list");
initbuf(&buf);
for(; l != nil; l = l->d){
if(atom(l)){
freebuf(&buf);
err("error: no list");
}
if(symbolp(l->a))
pushchar(&buf, getpname(l->a)->str[0]);
else if(fixnump(l->a))
pushchar(&buf, l->a->fix);
else{
freebuf(&buf);
err("error: not an ascii character");
}
}
pushchar(&buf, '\0');
return buf;
}
C *ascii_subr(void){
if(!fixnump(alist[0])) err("error: not a fixnum");
return mkchar(alist[0]->fix);
}
C *maknam_subr(void){
C *l;
Strbuf buf;
buf = list2str(alist[0]);
l = mksym(buf.buf);
freebuf(&buf);
return l;
}
C *implode_subr(void){
alist[0] = maknam_subr();
return intern_subr();
}
C *explode_aux(void (*prnt)(C*), C *(*f)(char)){
C *s;
Stream strsv;
strsv = sysout;
sysout.type = IO_BUF;
initbuf(&sysout.strbuf);
prnt(alist[0]);
tyo('\0');
s = str2list(sysout.strbuf.buf, f);
freebuf(&sysout.strbuf);
sysout = strsv;
return s;
}
C *explode_subr(void){ return explode_aux(lprint, mkchar); }
C *explodec_subr(void){ return explode_aux(princ, mkchar); }
C *exploden_subr(void){ return explode_aux(princ, mkfixchar); }
C *flat_aux(void (*prnt)(C*)){
C *s;
Stream strsv;
strsv = sysout;
sysout.type = IO_BUF;
initbuf(&sysout.strbuf);
prnt(alist[0]);
tyo('\0');
s = mkfix(strlen(sysout.strbuf.buf));
freebuf(&sysout.strbuf);
sysout = strsv;
return s;
}
C *flatc_subr(void){ return flat_aux(princ); }
C *flatsize_subr(void){ return flat_aux(lprint); }
C *readlist_subr(void){
C *l;
Strbuf buf;
Stream strsv;
buf = list2str(alist[0]);
buf.len = buf.pos;
buf.pos = 0;
strsv = sysin;
sysin.type = IO_BUF;
sysin.strbuf = buf;
sysin.nextc = 0;
// Be careful to clean up after errors here
errsp++;
if(setjmp(errlabel[errsp])){
errsp--;
sysin = strsv;
freebuf(&buf);
longjmp(errlabel[errsp], 1);
}
l = readsxp(1);
errsp--;
sysin = strsv;
freebuf(&buf);
return l;
}
/* Mapping */
/* zip is for internal use.
* It returns successively zipped lists for mapping
* leaving the list on the stack. */
static int
zip(C *(*f)(C*))
{
int i;
C **ap;
ap = push(nil);
for(i = 2; i <= largs.nargs; i++){
if(largs.alist[i] == nil){
pop();
return 1;
}
*ap = cons(f(largs.alist[i]), nil);
ap = &(*ap)->d;
largs.alist[i] = largs.alist[i]->d;
}
return 0;
}
C *id(C *c) { return c; }
static int ziplist(void){ return zip(id); }
static int zipcar(void){ return zip(car); }
C *maplist_aux(int (*zip)(void)){
C **p;
if(largs.nargs < 2)
err("error: arg count");
p = push(nil);
while(!zip()){
*p = cons(apply(largs.alist[1], pop(), nil), nil);
p = &(*p)->d;
}
return pop();
}
C *maplist_lsubr(void){ return maplist_aux(ziplist); }
C *mapcar_lsubr(void){ return maplist_aux(zipcar); }
C *map_aux(int (*zip)(void)){
C *ret;
if(largs.nargs < 2)
err("error: arg count");
ret = largs.alist[2];
while(!zip())
apply(largs.alist[1], pop(), nil);
return ret;
}
C *map_lsubr(void){ return map_aux(ziplist); }
C *mapc_lsubr(void){ return map_aux(zipcar); }
C *mapcon_aux(int (*zip)(void)){
C **p;
if(largs.nargs < 2)
err("error: arg count");
p = push(nil);
while(!zip()){
*p = apply(largs.alist[1], pop(), nil);
for(; *p != nil; p = &(*p)->d)
if(atom(*p))
err("error: no list");
}
return pop();
}
C *mapcon_lsubr(void){ return mapcon_aux(ziplist); }
C *mapcan_lsubr(void){ return mapcon_aux(zipcar); }
/* IO */
C *read_subr(void){
return readsxp(1);
}
C *prin1_subr(void){
lprint(alist[0]);
return t;
}
C *print_subr(void){
tyo('\n');
lprint(alist[0]);
tyo(' ');
return t;
}
C *princ_subr(void){
princ(alist[0]);
return t;
}
C *terpri_subr(void){
tyo('\n');
return nil;
}
/* Prog feature */
Prog prog;
C *go_fsubr(void){
C *tt, *p;
if(prog.prog == nil)
err("error: not in prog");
if(alist[0] == nil)
err("error: arg count");
tt = alist[0]->a;
while(!atom(tt))
tt = eval(tt, alist[1]);
for(p = prog.prog; p != nil; p = p->d)
if(p->a == tt){
prog.pc = p->d;
return nil;
}
err("undefined label");
return nil; // hm...
}
C *return_fsubr(void){
if(prog.prog == nil)
err("error: not in prog");
if(alist[0] == nil)
prog.ret = nil;
else
prog.ret = eval(alist[0]->a, alist[1]);
prog.pc = nil;
return nil; // hm...
}
C *prog_fsubr(void){
Prog progsv;
C *p, *a;
C **ap;
progsv = prog;
prog.prog = alist[0]->d;
prog.pc = alist[0]->d;
/* build a-list */
assert(temlis.a == nil);
ap = (C**)&temlis.a;
for(p = alist[0]->a; p != nil; p = p->d){
*ap = cons(cons(p->a, nil), nil);
ap = &(*ap)->d;
}
*ap = alist[1]; /* nconc */
alist[1] = a = temlis.a;
temlis.a = nil;
/* execute */
prog.ret = nil;
while(prog.pc != nil){
p = prog.pc->a;
prog.pc = prog.pc->d;
if(!atom(p))
eval(p, a);
}
p = prog.ret;
prog = progsv;
return p;
}
void
initsubr(void)
{
C *a;
putprop(t, t, value);
#define SUBR(str, func, narg) \
a = intern(str); \
putprop(a, mksubr(func, narg), subr);
#define LSUBR(str, func) \
a = intern(str); \
putprop(a, mksubr(func, -1), lsubr);
#define FSUBR(str, func) \
a = intern(str); \
putprop(a, (C*)consw((word)func), fsubr);
SUBR("ATOM", atom_subr, 1)
SUBR("FIXP", fixp_subr, 1)
SUBR("FLOATP", floatp_subr, 1)
SUBR("NUMBERP", numberp_subr, 1)
SUBR("STRINGP", stringp_subr, 1)
SUBR("APPLY", apply_subr, 3)
SUBR("EVAL", eval_subr, 2)
FSUBR("QUOTE", quote_fsubr)
FSUBR("FUNCTION", function_fsubr)
FSUBR("COMMENT", comment_fsubr)
LSUBR("PROG2", prog2_lsubr)
LSUBR("PROGN", progn_lsubr)
SUBR("ARG", arg_subr, 1)
SUBR("CAR", car_subr, 1)
SUBR("CDR", cdr_subr, 1)
SUBR("CAAR", caar_subr, 1)
SUBR("CADR", cadr_subr, 1)
SUBR("CDAR", cdar_subr, 1)
SUBR("CDDR", cddr_subr, 1)
SUBR("CAAAR", caaar_subr, 1)
SUBR("CAADR", caadr_subr, 1)
SUBR("CADAR", cadar_subr, 1)
SUBR("CADDR", caddr_subr, 1)
SUBR("CDAAR", cdaar_subr, 1)
SUBR("CDADR", cdadr_subr, 1)
SUBR("CDDAR", cddar_subr, 1)
SUBR("CDDDR", cdddr_subr, 1)
SUBR("CAAAAR", caaaar_subr, 1)
SUBR("CAAADR", caaadr_subr, 1)
SUBR("CAADAR", caadar_subr, 1)
SUBR("CAADDR", caaddr_subr, 1)
SUBR("CADAAR", cadaar_subr, 1)
SUBR("CADADR", cadadr_subr, 1)
SUBR("CADDAR", caddar_subr, 1)
SUBR("CADDDR", cadddr_subr, 1)
SUBR("CDAAAR", cdaaar_subr, 1)
SUBR("CDAADR", cdaadr_subr, 1)
SUBR("CDADAR", cdadar_subr, 1)
SUBR("CDADDR", cdaddr_subr, 1)
SUBR("CDDAAR", cddaar_subr, 1)
SUBR("CDDADR", cddadr_subr, 1)
SUBR("CDDDAR", cdddar_subr, 1)
SUBR("CDDDDR", cddddr_subr, 1)
SUBR("EQ", eq_subr, 2)
SUBR("EQUAL", equal_subr, 2)
SUBR("ASSOC", assoc_subr, 2)
SUBR("ASSQ", assq_subr, 2)
SUBR("SASSOC", sassoc_subr, 3)
SUBR("SASSQ", sassq_subr, 3)
SUBR("LAST", last_subr, 1)
SUBR("LENGTH", length_subr, 1)
SUBR("MEMBER", member_subr, 2)
SUBR("MEMQ", memq_subr, 2)
SUBR("NOT", null_subr, 1)
SUBR("NULL", null_subr, 1)
SUBR("CONS", cons_subr, 2)
SUBR("NCONS", ncons_subr, 1)
SUBR("XCONS", xcons_subr, 2)
FSUBR("LIST", list_fsubr)
SUBR("APPEND", append_subr, 2)
SUBR("REVERSE", reverse_subr, 1)
SUBR("RPLACA", rplaca_subr, 2)
SUBR("RPLACD", rplacd_subr, 2)
SUBR("NCONC", nconc_subr, 2)
SUBR("NREVERSE", nreverse_subr, 1)
LSUBR("DELETE", delete_lsubr)
LSUBR("DELQ", delq_lsubr)
FSUBR("AND", and_fsubr)
FSUBR("OR", or_fsubr)
FSUBR("PROG", prog_fsubr)
FSUBR("RETURN", return_fsubr)
FSUBR("GO", go_fsubr)
FSUBR("SETQ", setq_fsubr)
FSUBR("SET", set_fsubr)
SUBR("BOUNDP", boundp_subr, 1);
SUBR("MAKUNBOUND", makunbound_subr, 1);
SUBR("GET", get_subr, 2)
SUBR("GETL", getl_subr, 2)
SUBR("PUTPROP", putprop_subr, 3)
FSUBR("DEFPROP", defprop_fsubr)
SUBR("REMPROP", remprop_subr, 2)
SUBR("SAMEPNAMEP", samepnamep_subr, 2)
SUBR("ALPHALESSP", alphalessp_subr, 2)
SUBR("GETCHAR", getchar_subr, 2)
SUBR("INTERN", intern_subr, 1)
SUBR("REMOB", remob_subr, 1)
LSUBR("GENSYM", gensym_lsubr)
SUBR("ZEROP", zerop_subr, 1)
SUBR("PLUSP", plusp_subr, 1)
SUBR("MINUSP", minusp_subr, 1)
LSUBR("<", lessp_lsubr)
LSUBR(">", greaterp_lsubr)
LSUBR("MAX", max_lsubr)
LSUBR("MIN", min_lsubr)
LSUBR("+", plus_lsubr)
LSUBR("-", difference_lsubr)
LSUBR("*", times_lsubr)
LSUBR("/", quotient_lsubr)
SUBR("1+", add1_subr, 1)
SUBR("1-", sub1_subr, 1)
SUBR("\\", remainder_subr, 2)
SUBR("EXPT", expt_subr, 2)
LSUBR("LOGIOR", logior_lsubr)
LSUBR("LOGAND", logand_lsubr)
LSUBR("LOGXOR", logxor_lsubr)
SUBR("LSH", lsh_subr, 2)
SUBR("ASCII", ascii_subr, 1)
SUBR("MAKNAM", maknam_subr, 1)
SUBR("IMPLODE", implode_subr, 1)
SUBR("EXPLODE", explode_subr, 1)
SUBR("EXPLODEC", explodec_subr, 1)
SUBR("EXPLODEN", exploden_subr, 1)
SUBR("FLATC", flatc_subr, 1)
SUBR("FLATSIZE", flatsize_subr, 1)
SUBR("READLIST", readlist_subr, 1)
LSUBR("MAPLIST", maplist_lsubr)
LSUBR("MAPCAR", mapcar_lsubr)
LSUBR("MAP", map_lsubr)
LSUBR("MAPC", mapc_lsubr)
LSUBR("MAPCON", mapcon_lsubr)
LSUBR("MAPCAN", mapcan_lsubr)
SUBR("READ", read_subr, 0)
SUBR("PRIN1", prin1_subr, 1)
SUBR("PRINT", print_subr, 1)
SUBR("PRINC", princ_subr, 1)
SUBR("TERPRI", terpri_subr, 0)
}