|
|
BSD 4.2
#ifndef lint
static char *rcsid =
"$Header: /var/lib/cvsd/repos/CSRG/42BSD/ucb/lisp/franz/lam5.c,v 1.1.1.1 2018/04/24 16:12:54 root Exp $";
#endif
/* -[Fri Aug 5 12:49:06 1983 by jkf]-
* lam5.c $Locker: $
* lambda functions
*
* (c) copyright 1982, Regents of the University of California
*/
#include "global.h"
#include "chkrtab.h"
#include <ctype.h>
char *strcpy(), *sprintf();
/*===========================================
-
- explode functions: aexplode , aexplodec, aexploden
- The following function partially implement the explode functions for atoms.
- The full explode functions are written in lisp and call these for atom args.
-
-===========================================*/
#include "chars.h"
lispval
Lexpldx(kind,slashify)
int kind, slashify; /* kind = 0 => explode to characters
= 1 => explode to fixnums (aexploden)
slashify = 0 => do not quote bizarre characters
= 1 => quote bizarre characters
*/
{
int typ, i;
char ch, *strb, strbb[BUFSIZ], *alloca(); /* temporary string buffer */
register lispval last, handy;
extern int uctolc;
register char *cp;
#ifdef SPISFP
Keepxs();
#endif
Savestack(3); /* kludge register save mask */
chkarg(1,"expldx");
handy = Vreadtable->a.clb;
chkrtab(handy);
handy = lbot->val;
*strbuf = 0;
typ=TYPE(handy); /* we only work for a few types */
/* put the characters to return in the string buffer strb */
switch(typ) {
case STRNG:
if(slashify && !Xsdc)
errorh1(Vermisc,"Can't explode without string delimiter",nil
,FALSE,0,handy);
strb = strbb;
if(slashify) *strb++ = Xsdc;
/* copy string into buffer, escape only occurances of the
double quoting character if in slashify mode
*/
for(cp = (char *) handy; *cp; cp++)
{
if(slashify &&
(*cp == Xsdc || synclass(ctable[*cp])==CESC))
*strb++ = Xesc;
*strb++ = *cp;
}
if(slashify) *strb++ = Xsdc;
*strb = NULL_CHAR ;
strb = strbb;
break;
case ATOM:
strb = handy->a.pname;
if(slashify && (strb[0]==0)) {
strb = strbb;
strbb[0] = Xdqc;
strbb[1] = Xdqc;
strbb[2] = 0;
} else
/*common:*/
if(slashify != 0)
{
char *out = strbb;
unsigned char code;
cp = strb;
strb = strbb;
code = ctable[(*cp)&0177];
switch(synclass(code)) {
case CNUM:
*out++ = Xesc;
break;
case CCHAR:
if(uctolc && isupper((*cp)&0177)) {
*out++ = Xesc;
}
break;
default:
switch(code&QUTMASK) {
case QWNUNIQ:
if (cp[1]==0) *out++ = Xesc;
break;
case QALWAYS:
case QWNFRST:
*out++ = Xesc;
}
}
*out++ = *cp++;
for(; *cp; cp++)
{
if(((ctable[*cp]&QUTMASK)==QALWAYS) ||
(uctolc && isupper(*cp)))
*out++ = Xesc;
*out++ = *cp;
}
*out = 0;
}
break;
case INT:
strb = strbb;
sprintf(strb, "%d", lbot->val->i);
break;
case DOUB:
strb = strbb;
lfltpr(strb, lbot->val->r);
break;
case SDOT:
{
struct _iobuf _strbuf;
int count;
for((handy = lbot->val), count = 12;
handy->s.CDR!=(lispval) 0;
(handy = handy->s.CDR), count += 12);
strb = alloca(count);
_strbuf._flag = _IOWRT+_IOSTRG;
_strbuf._ptr = strb;
_strbuf._cnt = count;
pbignum(lbot->val,&_strbuf);
putc(0,&_strbuf);
break;
}
default:
errorh1(Vermisc,"EXPLODE ARG MUST BE STRING, SYMBOL, FIXNUM, OR FLONUM",nil,FALSE,0,handy);
Restorestack();
Freexs();
return(nil);
}
if( strb[0] != NULL_CHAR ) /* if there is something to do */
{
lispval prev;
protect(handy = last = newdot());
strbuf[1] = NULL_CHAR ; /* set up for getatom */
atmlen = 2;
for(i=0; ch = strb[i++]; ) {
switch(kind) {
case 0: strbuf[0] = hash = ch; /* character explode */
last->d.car = (lispval) getatom(TRUE); /* look in oblist */
break;
case 1:
last->d.car = inewint(ch);
break;
}
/* advance pointers */
prev = last;
last->d.cdr = newdot();
last = last->d.cdr;
}
/* end list with a nil pointer */
prev->d.cdr = nil;
Freexs();
Restorestack();
return(handy);
}
Freexs();
Restorestack();
return(nil); /* return nil if no characters */
}
/*===========================
-
- (aexplodec 'atm) returns (a t m)
- (aexplodec 234) returns (\2 \3 \4)
-===========================*/
lispval
Lexpldc()
{ return(Lexpldx(0,0)); }
/*===========================
-
- (aexploden 'abc) returns (65 66 67)
- (aexploden 123) returns (49 50 51)
-=============================*/
lispval
Lexpldn()
{ return(Lexpldx(1,0)); }
/*===========================
-
- (aexplode "123") returns (\\ \1 \2 \3);
- (aexplode 123) returns (\1 \2 \3);
-=============================*/
lispval
Lexplda()
{ return(Lexpldx(0,1)); }
/*
* (argv) returns how many arguments where on the command line which invoked
* lisp; (argv i) returns the i'th argument made into an atom;
*/
lispval
Largv()
{
register lispval handy;
extern int Xargc;
extern char **Xargv;
if(lbot-np==0)handy = nil;
else handy = lbot->val;
if(TYPE(handy)==INT && handy->i>=0 && handy->i<Xargc) {
strcpy(strbuf,Xargv[handy->i]);
return(getatom(FALSE));
} else {
return(inewint(Xargc));
}
}
/*
* (chdir <atom>) executes a chdir command
* if successful, return t otherwise returns nil
*/
lispval Lchdir(){
register char *filenm;
chkarg(1,"chdir");
filenm = (char *) verify(lbot->val,"chdir - non symbol or string arg");
if(chdir(filenm)>=0)
return(tatom);
else
return(nil);
}
/* ==========================================================
-
- ascii - convert from number to ascii character
-
- form:(ascii number)
-
- the number is checked so that it is in the range 0-255
- then it is made a character and returned
- =========================================================*/
lispval
Lascii()
{
register lispval handy;
handy = lbot->val; /* get argument */
if(TYPE(handy) != INT) /* insure that it is an integer */
{ error("argument not an integer",FALSE);
return(nil);
}
if(handy->i < 0 || handy->i > 0377) /* insure that it is in range*/
{ error("argument is out of ascii range",FALSE);
return(nil);
}
strbuf[0] = handy->i ; /* ok value, make into a char */
strbuf[1] = NULL_CHAR;
/* lookup and possibly intern the atom given in strbuf */
return( (lispval) getatom(TRUE) );
}
/*
* boole - maclisp bitwise boolean function
* (boole k x y) where k determines which of 16 possible bitwise
* truth tables may be applied. Common values are 1 (and) 6 (xor) 7 (or)
* the result is mapped over each pair of bits on input
*/
lispval
Lboole(){
register x, y;
register struct argent *mynp;
int k;
if(np - lbot < 3)
error("Boole demands at least 3 args",FALSE);
mynp = lbot+AD;
k = mynp->val->i & 15;
x = (mynp+1)->val->i;
for(mynp += 2; mynp < np; mynp++) {
y = mynp->val->i;
switch(k) {
case 0: x = 0;
break;
case 1: x = x & y;
break;
case 2: x = y & ~x;
break;
case 3: x = y;
break;
case 4: x = x & ~y;
break;
/* case 5: x = x; break; */
case 6: x = x ^ y;
break;
case 7: x = x | y;
break;
case 8: x = ~(x | y);
break;
case 9: x = ~(x ^ y);
break;
case 10: x = ~x;
break;
case 11: x = ~x | y;
break;
case 12: x = ~y;
break;
case 13: x = x | ~y;
break;
case 14: x = ~x | ~y;
break;
case 15: x = -1;
}
}
return(inewint(x));
}
lispval
Lfact()
{
register lispval result, handy;
register itemp;
Savestack(3); /* fixup entry mask */
result = lbot->val;
if(TYPE(result)!=INT) error("Factorial of Non-fixnum. If you want me\
to calculate fact of > 2^30 We will be here till doomsday!.",FALSE);
itemp = result->i;
protect(result = newsdot());
result->s.CDR=(lispval)0;
result->i = 1;
for(; itemp > 1; itemp--)
dmlad(result,(long)itemp,0L);
if(result->s.CDR)
{
Restorestack();
return(result);
}
handy = inewint(result->s.I);
pruneb(result);
Restorestack();
return(handy);
}
/*
* fix -- maclisp floating to fixnum conversion
* for the moment, mereley convert floats to ints.
* eventual convert to bignum if too big to fit.
*/
lispval Lfix()
{
register lispval handy;
double floor();
chkarg(1,"fix");
handy = lbot->val;
switch(TYPE(handy)) {
default:
error("innaproriate arg to fix.",FALSE);
case INT:
case SDOT:
return(handy);
case DOUB:
return(inewint((int)floor(handy->r)));
}
}
/*
* (frexp <real no>)
* returns a dotted pair (<exponent>. <bignum>)
* such that bignum is 56 bits long, and if you think of the binary
* point occuring after the high order bit, <real no> = 2^<exp> * <bignum>
*
* myfrexp is an assembly language routine found in bigmath.s to do exactly
* what is necessary to accomplish this.
* this routine is horribly vax specific.
*
* Lfix should probably be rewritten to take advantage of myfrexp
*/
lispval
Lfrexp()
{
register lispval handy, result;
int exp, hi, lo;
Savestack(2);
chkarg(1,"frexp");
myfrexp(lbot->val->r, &exp, &hi, &lo);
if(lo < 0) {
/* normalize for bignum */
lo &= ~ 0xC0000000;
hi += 1;
}
result = handy = newdot();
protect(handy);
handy->d.car = inewint(exp);
if(hi==0&&lo==0) {
handy->d.cdr = inewint(0);
} else {
handy = handy->d.cdr = newsdot();
handy->s.I = lo;
handy = handy->s.CDR = newdot();
handy->s.I = hi;
handy->s.CDR = 0;
}
np--;
Restorestack();
return(result);
}
#define SIGFPE 8
#define B 1073741824.0
static double table[] = { 1.0, B, B*B, B*B*B, B*B*B*B, 0.0};
lispval
Lfloat()
{
register lispval handy,result;
register double sum = 0;
register int count;
chkarg(1,"float");
handy = lbot->val;
switch(TYPE(handy))
{
case DOUB: return(handy);
case INT: result = newdoub();
result->r = (double) handy->i;
return(result);
case SDOT:
{
for(handy = lbot->val, count = 0;
count < 5;
count++, handy = handy->s.CDR) {
sum += handy->s.I * table[count];
if(handy->s.CDR==(lispval)0) goto done;
}
kill(getpid(),SIGFPE);
done:
result = newdoub();
result->r = sum;
return(result);
}
default: errorh1(Vermisc,"Bad argument to float",nil,FALSE,0,handy);
/* NOTREACHED */
}
}
double
Ifloat(handy)
register lispval handy;
{
register double sum = 0.0; register int count=0;
for(; count < 5; count++, handy = handy->s.CDR) {
sum += handy->s.I * table[count];
if(handy->s.CDR==(lispval)0) goto done;
}
kill(getpid(),SIGFPE);
done:
return(sum);
}
/* Lbreak ***************************************************************/
/* If first argument is not nil, this is evaluated and printed. Then */
/* error is called with the "breaking" message. */
lispval Lbreak() {
if (np > lbot) {
printr(lbot->val,poport);
dmpport(poport);
}
return(error("",TRUE));
}
lispval
LDivide() {
register lispval result, work;
register struct argent *mynp;
lispval quo, rem, arg1, arg2; struct sdot dummy, dum2;
Savestack(3);
chkarg(2,"Divide");
mynp = lbot;
work = mynp++->val;
switch(TYPE(work)) {
case INT:
arg1 = (lispval) &dummy;
dummy.I = work->i;
dummy.CDR = (lispval) 0;
break;
case SDOT:
arg1 = work;
break;
urk:
default:
error("First arg to divide neither a bignum nor int.",FALSE);
}
work = mynp->val;
switch(TYPE(work)) {
case INT:
arg2 = (lispval) &dum2;
dum2.I = work->i;
dum2.CDR = (lispval) 0;
break;
case SDOT:
arg2 = work;
break;
default:
goto urk;
}
divbig(arg1,arg2, &quo, &rem);
protect(quo);
if(rem==((lispval)&dummy))
rem = inewint(dummy.I);
protect(rem);
protect(result = work = newdot());
work->d.car = quo;
(work->d.cdr = newdot())->d.car = rem;
Restorestack();
return(result);
}
lispval LEmuldiv(){
register struct argent * mynp = lbot+AD;
register lispval work, result;
int quo, rem;
Savestack(3); /* fix register mask */
/* (Emuldiv mul1 mult2 add quo) =>
temp = mul1 + mul2 + sext(add);
result = (list temp/quo temp%quo);
to mix C and lisp a bit */
Imuldiv(mynp[0].val->i, mynp[1].val->i, mynp[2].val->i,
mynp[3].val->i, &quo, &rem);
protect(result=newdot());
(result->d.car=inewint(quo));
work = result->d.cdr = newdot();
(work->d.car=inewint(rem));
Restorestack();
return(result);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.