Commit | Line | Data |
---|---|---|
64a4bc62 C |
1 | #ifndef lint |
2 | static char *rcsid = | |
3 | "$Header: lam5.c,v 1.8 87/12/14 18:47:45 sklower Exp $"; | |
4 | #endif | |
5 | ||
6 | /* -[Fri Aug 5 12:49:06 1983 by jkf]- | |
7 | * lam5.c $Locker: $ | |
8 | * lambda functions | |
9 | * | |
10 | * (c) copyright 1982, Regents of the University of California | |
11 | */ | |
12 | ||
13 | #include "global.h" | |
14 | #include "chkrtab.h" | |
15 | #include <ctype.h> | |
16 | char *strcpy(); | |
17 | ||
18 | /*=========================================== | |
19 | - | |
20 | - explode functions: aexplode , aexplodec, aexploden | |
21 | - The following function partially implement the explode functions for atoms. | |
22 | - The full explode functions are written in lisp and call these for atom args. | |
23 | - | |
24 | -===========================================*/ | |
25 | ||
26 | #include "chars.h" | |
27 | lispval | |
28 | Lexpldx(kind,slashify) | |
29 | int kind, slashify; /* kind = 0 => explode to characters | |
30 | = 1 => explode to fixnums (aexploden) | |
31 | slashify = 0 => do not quote bizarre characters | |
32 | = 1 => quote bizarre characters | |
33 | */ | |
34 | { | |
35 | int typ, i; | |
36 | char ch, *strb, strbb[BUFSIZ], *alloca(); /* temporary string buffer */ | |
37 | register lispval last, handy; | |
38 | extern int uctolc; | |
39 | register char *cp; | |
40 | Savestack(3); /* kludge register save mask */ | |
41 | #ifdef SPISFP | |
42 | Keepxs(); | |
43 | #endif | |
44 | ||
45 | chkarg(1,"expldx"); | |
46 | ||
47 | handy = Vreadtable->a.clb; | |
48 | chkrtab(handy); | |
49 | handy = lbot->val; | |
50 | *strbuf = 0; | |
51 | typ=TYPE(handy); /* we only work for a few types */ | |
52 | ||
53 | ||
54 | /* put the characters to return in the string buffer strb */ | |
55 | ||
56 | switch(typ) { | |
57 | case STRNG: | |
58 | if(slashify && !Xsdc) | |
59 | errorh1(Vermisc,"Can't explode without string delimiter",nil | |
60 | ,FALSE,0,handy); | |
61 | ||
62 | strb = strbb; | |
63 | if(slashify) *strb++ = Xsdc; | |
64 | /* copy string into buffer, escape only occurances of the | |
65 | double quoting character if in slashify mode | |
66 | */ | |
67 | for(cp = (char *) handy; *cp; cp++) | |
68 | { | |
69 | if(slashify && | |
70 | (*cp == Xsdc || synclass(ctable[*cp])==CESC)) | |
71 | *strb++ = Xesc; | |
72 | *strb++ = *cp; | |
73 | } | |
74 | if(slashify) *strb++ = Xsdc; | |
75 | *strb = NULL_CHAR ; | |
76 | strb = strbb; | |
77 | break; | |
78 | ||
79 | case ATOM: | |
80 | strb = handy->a.pname; | |
81 | if(slashify && (strb[0]==0)) { | |
82 | strb = strbb; | |
83 | strbb[0] = Xdqc; | |
84 | strbb[1] = Xdqc; | |
85 | strbb[2] = 0; | |
86 | } else | |
87 | /*common:*/ | |
88 | if(slashify != 0) | |
89 | { | |
90 | char *out = strbb; | |
91 | unsigned char code; | |
92 | ||
93 | cp = strb; | |
94 | strb = strbb; | |
95 | code = ctable[(*cp)&0177]; | |
96 | switch(synclass(code)) { | |
97 | case CNUM: | |
98 | *out++ = Xesc; | |
99 | break; | |
100 | case CCHAR: | |
101 | if(uctolc && isupper((*cp)&0177)) { | |
102 | *out++ = Xesc; | |
103 | } | |
104 | break; | |
105 | default: | |
106 | switch(code&QUTMASK) { | |
107 | case QWNUNIQ: | |
108 | if (cp[1]==0) *out++ = Xesc; | |
109 | break; | |
110 | case QALWAYS: | |
111 | case QWNFRST: | |
112 | *out++ = Xesc; | |
113 | } | |
114 | } | |
115 | *out++ = *cp++; | |
116 | for(; *cp; cp++) | |
117 | { | |
118 | if(((ctable[*cp]&QUTMASK)==QALWAYS) || | |
119 | (uctolc && isupper(*cp))) | |
120 | *out++ = Xesc; | |
121 | *out++ = *cp; | |
122 | } | |
123 | *out = 0; | |
124 | } | |
125 | break; | |
126 | ||
127 | case INT: | |
128 | strb = strbb; | |
129 | sprintf(strb, "%d", lbot->val->i); | |
130 | break; | |
131 | case DOUB: | |
132 | strb = strbb; | |
133 | lfltpr(strb, lbot->val->r); | |
134 | break; | |
135 | case SDOT: | |
136 | { | |
137 | struct _iobuf _strbuf; | |
138 | int count; | |
139 | for((handy = lbot->val), count = 12; | |
140 | handy->s.CDR!=(lispval) 0; | |
141 | (handy = handy->s.CDR), count += 12); | |
142 | strb = alloca(count); | |
143 | ||
144 | _strbuf._flag = _IOWRT+_IOSTRG; | |
145 | _strbuf._ptr = strb; | |
146 | _strbuf._cnt = count; | |
147 | pbignum(lbot->val,&_strbuf); | |
148 | putc(0,&_strbuf); | |
149 | break; | |
150 | } | |
151 | default: | |
152 | errorh1(Vermisc,"EXPLODE ARG MUST BE STRING, SYMBOL, FIXNUM, OR FLONUM",nil,FALSE,0,handy); | |
153 | Restorestack(); | |
154 | Freexs(); | |
155 | return(nil); | |
156 | } | |
157 | ||
158 | ||
159 | if( strb[0] != NULL_CHAR ) /* if there is something to do */ | |
160 | { | |
161 | lispval prev; | |
162 | ||
163 | protect(handy = last = newdot()); | |
164 | strbuf[1] = NULL_CHAR ; /* set up for getatom */ | |
165 | atmlen = 2; | |
166 | ||
167 | for(i=0; ch = strb[i++]; ) { | |
168 | switch(kind) { | |
169 | ||
170 | case 0: strbuf[0] = hash = ch; /* character explode */ | |
171 | last->d.car = (lispval) getatom(TRUE); /* look in oblist */ | |
172 | break; | |
173 | ||
174 | case 1: | |
175 | last->d.car = inewint(ch); | |
176 | break; | |
177 | } | |
178 | ||
179 | /* advance pointers */ | |
180 | prev = last; | |
181 | last->d.cdr = newdot(); | |
182 | last = last->d.cdr; | |
183 | } | |
184 | ||
185 | /* end list with a nil pointer */ | |
186 | prev->d.cdr = nil; | |
187 | Freexs(); | |
188 | Restorestack(); | |
189 | return(handy); | |
190 | } | |
191 | Freexs(); | |
192 | Restorestack(); | |
193 | return(nil); /* return nil if no characters */ | |
194 | } | |
195 | ||
196 | /*=========================== | |
197 | - | |
198 | - (aexplodec 'atm) returns (a t m) | |
199 | - (aexplodec 234) returns (\2 \3 \4) | |
200 | -===========================*/ | |
201 | ||
202 | lispval | |
203 | Lxpldc() | |
204 | { return(Lexpldx(0,0)); } | |
205 | ||
206 | ||
207 | /*=========================== | |
208 | - | |
209 | - (aexploden 'abc) returns (65 66 67) | |
210 | - (aexploden 123) returns (49 50 51) | |
211 | -=============================*/ | |
212 | ||
213 | ||
214 | lispval | |
215 | Lxpldn() | |
216 | { return(Lexpldx(1,0)); } | |
217 | ||
218 | /*=========================== | |
219 | - | |
220 | - (aexplode "123") returns (\\ \1 \2 \3); | |
221 | - (aexplode 123) returns (\1 \2 \3); | |
222 | -=============================*/ | |
223 | ||
224 | lispval | |
225 | Lxplda() | |
226 | { return(Lexpldx(0,1)); } | |
227 | ||
228 | /* | |
229 | * (argv) returns how many arguments where on the command line which invoked | |
230 | * lisp; (argv i) returns the i'th argument made into an atom; | |
231 | */ | |
232 | ||
233 | lispval | |
234 | Largv() | |
235 | { | |
236 | register lispval handy; | |
237 | extern int Xargc; | |
238 | extern char **Xargv; | |
239 | ||
240 | if(lbot-np==0)handy = nil; | |
241 | else handy = lbot->val; | |
242 | ||
243 | if(TYPE(handy)==INT && handy->i>=0 && handy->i<Xargc) { | |
244 | strcpy(strbuf,Xargv[handy->i]); | |
245 | return(getatom(FALSE)); | |
246 | } else { | |
247 | return(inewint(Xargc)); | |
248 | } | |
249 | } | |
250 | /* | |
251 | * (chdir <atom>) executes a chdir command | |
252 | * if successful, return t otherwise returns nil | |
253 | */ | |
254 | lispval Lchdir(){ | |
255 | register char *filenm; | |
256 | ||
257 | chkarg(1,"chdir"); | |
258 | filenm = (char *) verify(lbot->val,"chdir - non symbol or string arg"); | |
259 | if(chdir(filenm)>=0) | |
260 | return(tatom); | |
261 | else | |
262 | return(nil); | |
263 | } | |
264 | ||
265 | /* ========================================================== | |
266 | - | |
267 | - ascii - convert from number to ascii character | |
268 | - | |
269 | - form:(ascii number) | |
270 | - | |
271 | - the number is checked so that it is in the range 0-255 | |
272 | - then it is made a character and returned | |
273 | - =========================================================*/ | |
274 | ||
275 | lispval | |
276 | Lascii() | |
277 | { | |
278 | register lispval handy; | |
279 | ||
280 | handy = lbot->val; /* get argument */ | |
281 | ||
282 | if(TYPE(handy) != INT) /* insure that it is an integer */ | |
283 | { error("argument not an integer",FALSE); | |
284 | return(nil); | |
285 | } | |
286 | ||
287 | if(handy->i < 0 || handy->i > 0377) /* insure that it is in range*/ | |
288 | { error("argument is out of ascii range",FALSE); | |
289 | return(nil); | |
290 | } | |
291 | ||
292 | strbuf[0] = handy->i ; /* ok value, make into a char */ | |
293 | strbuf[1] = NULL_CHAR; | |
294 | ||
295 | /* lookup and possibly intern the atom given in strbuf */ | |
296 | ||
297 | return( (lispval) getatom(TRUE) ); | |
298 | } | |
299 | ||
300 | /* | |
301 | * boole - maclisp bitwise boolean function | |
302 | * (boole k x y) where k determines which of 16 possible bitwise | |
303 | * truth tables may be applied. Common values are 1 (and) 6 (xor) 7 (or) | |
304 | * the result is mapped over each pair of bits on input | |
305 | */ | |
306 | lispval | |
307 | Lboole(){ | |
308 | register x, y; | |
309 | register struct argent *mynp; | |
310 | int k; | |
311 | ||
312 | if(np - lbot < 3) | |
313 | error("Boole demands at least 3 args",FALSE); | |
314 | mynp = lbot+AD; | |
315 | k = mynp->val->i & 15; | |
316 | x = (mynp+1)->val->i; | |
317 | for(mynp += 2; mynp < np; mynp++) { | |
318 | y = mynp->val->i; | |
319 | switch(k) { | |
320 | ||
321 | case 0: x = 0; | |
322 | break; | |
323 | case 1: x = x & y; | |
324 | break; | |
325 | case 2: x = y & ~x; | |
326 | break; | |
327 | case 3: x = y; | |
328 | break; | |
329 | case 4: x = x & ~y; | |
330 | break; | |
331 | /* case 5: x = x; break; */ | |
332 | case 6: x = x ^ y; | |
333 | break; | |
334 | case 7: x = x | y; | |
335 | break; | |
336 | case 8: x = ~(x | y); | |
337 | break; | |
338 | case 9: x = ~(x ^ y); | |
339 | break; | |
340 | case 10: x = ~x; | |
341 | break; | |
342 | case 11: x = ~x | y; | |
343 | break; | |
344 | case 12: x = ~y; | |
345 | break; | |
346 | case 13: x = x | ~y; | |
347 | break; | |
348 | case 14: x = ~x | ~y; | |
349 | break; | |
350 | case 15: x = -1; | |
351 | } | |
352 | } | |
353 | return(inewint(x)); | |
354 | } | |
355 | lispval | |
356 | Lfact() | |
357 | { | |
358 | register lispval result, handy; | |
359 | register itemp; | |
360 | Savestack(3); /* fixup entry mask */ | |
361 | ||
362 | result = lbot->val; | |
363 | if(TYPE(result)!=INT) error("Factorial of Non-fixnum. If you want me\ | |
364 | to calculate fact of > 2^30 We will be here till doomsday!.",FALSE); | |
365 | itemp = result->i; | |
366 | protect(result = newsdot()); | |
367 | result->s.CDR=(lispval)0; | |
368 | result->i = 1; | |
369 | for(; itemp > 1; itemp--) | |
370 | dmlad(result,(long)itemp,0L); | |
371 | if(result->s.CDR) | |
372 | { | |
373 | Restorestack(); | |
374 | return(result); | |
375 | } | |
376 | handy = inewint(result->s.I); | |
377 | pruneb(result); | |
378 | Restorestack(); | |
379 | return(handy); | |
380 | } | |
381 | /* | |
382 | * fix -- maclisp floating to fixnum conversion | |
383 | * for the moment, mereley convert floats to ints. | |
384 | * eventual convert to bignum if too big to fit. | |
385 | */ | |
386 | lispval Lfix() | |
387 | { | |
388 | register lispval handy; | |
389 | double floor(); | |
390 | ||
391 | chkarg(1,"fix"); | |
392 | handy = lbot->val; | |
393 | switch(TYPE(handy)) { | |
394 | default: | |
395 | error("innaproriate arg to fix.",FALSE); | |
396 | case INT: | |
397 | case SDOT: | |
398 | return(handy); | |
399 | case DOUB: | |
400 | return(inewint((int)floor(handy->r))); | |
401 | } | |
402 | } | |
403 | /* | |
404 | * (frexp <real no>) | |
405 | * returns a dotted pair (<exponent>. <bignum>) | |
406 | * such that bignum is 56 bits long, and if you think of the binary | |
407 | * point occuring after the high order bit, <real no> = 2^<exp> * <bignum> | |
408 | * | |
409 | * myfrexp is an assembly language routine found in bigmath.s to do exactly | |
410 | * what is necessary to accomplish this. | |
411 | * this routine is horribly vax specific. | |
412 | * | |
413 | * Lfix should probably be rewritten to take advantage of myfrexp | |
414 | */ | |
415 | lispval | |
416 | Lfrexp() | |
417 | { | |
418 | register lispval handy, result; | |
419 | int exp, hi, lo; | |
420 | ||
421 | Savestack(2); | |
422 | chkarg(1,"frexp"); | |
423 | ||
424 | myfrexp(lbot->val->r, &exp, &hi, &lo); | |
425 | if(lo < 0) { | |
426 | /* normalize for bignum */ | |
427 | lo &= ~ 0xC0000000; | |
428 | hi += 1; | |
429 | } | |
430 | result = handy = newdot(); | |
431 | protect(handy); | |
432 | handy->d.car = inewint(exp); | |
433 | if(hi==0&&lo==0) { | |
434 | handy->d.cdr = inewint(0); | |
435 | } else { | |
436 | handy = handy->d.cdr = newsdot(); | |
437 | handy->s.I = lo; | |
438 | handy = handy->s.CDR = newdot(); | |
439 | handy->s.I = hi; | |
440 | handy->s.CDR = 0; | |
441 | } | |
442 | np--; | |
443 | Restorestack(); | |
444 | return(result); | |
445 | } | |
446 | ||
447 | #define SIGFPE 8 | |
448 | #define B 1073741824.0 | |
449 | static double table[] = { 1.0, B, B*B, B*B*B, B*B*B*B, 0.0}; | |
450 | ||
451 | lispval | |
452 | Lfloat() | |
453 | { | |
454 | register lispval handy,result; | |
455 | register double sum = 0; | |
456 | register int count; | |
457 | chkarg(1,"float"); | |
458 | handy = lbot->val; | |
459 | switch(TYPE(handy)) | |
460 | { | |
461 | case DOUB: return(handy); | |
462 | ||
463 | ||
464 | case INT: result = newdoub(); | |
465 | result->r = (double) handy->i; | |
466 | return(result); | |
467 | case SDOT: | |
468 | { | |
469 | for(handy = lbot->val, count = 0; | |
470 | count < 5; | |
471 | count++, handy = handy->s.CDR) { | |
472 | sum += handy->s.I * table[count]; | |
473 | if(handy->s.CDR==(lispval)0) goto done; | |
474 | } | |
475 | kill(getpid(),SIGFPE); | |
476 | done: | |
477 | result = newdoub(); | |
478 | result->r = sum; | |
479 | return(result); | |
480 | } | |
481 | default: errorh1(Vermisc,"Bad argument to float",nil,FALSE,0,handy); | |
482 | /* NOTREACHED */ | |
483 | } | |
484 | } | |
485 | double | |
486 | Ifloat(handy) | |
487 | register lispval handy; | |
488 | { | |
489 | register double sum = 0.0; register int count=0; | |
490 | for(; count < 5; count++, handy = handy->s.CDR) { | |
491 | sum += handy->s.I * table[count]; | |
492 | if(handy->s.CDR==(lispval)0) goto done; | |
493 | } | |
494 | kill(getpid(),SIGFPE); | |
495 | done: | |
496 | return(sum); | |
497 | } | |
498 | ||
499 | /* Lbreak ***************************************************************/ | |
500 | /* If first argument is not nil, this is evaluated and printed. Then */ | |
501 | /* error is called with the "breaking" message. */ | |
502 | lispval Lbreak() { | |
503 | ||
504 | if (np > lbot) { | |
505 | printr(lbot->val,poport); | |
506 | dmpport(poport); | |
507 | } | |
508 | return(error("",TRUE)); | |
509 | } | |
510 | ||
511 | ||
512 | lispval | |
513 | LDivide() { | |
514 | register lispval result, work; | |
515 | register struct argent *mynp; | |
516 | lispval quo, rem, arg1, arg2; struct sdot dummy, dum2; | |
517 | Savestack(3); | |
518 | ||
519 | chkarg(2,"Divide"); | |
520 | mynp = lbot; | |
521 | work = mynp++->val; | |
522 | switch(TYPE(work)) { | |
523 | case INT: | |
524 | arg1 = (lispval) &dummy; | |
525 | dummy.I = work->i; | |
526 | dummy.CDR = (lispval) 0; | |
527 | break; | |
528 | case SDOT: | |
529 | arg1 = work; | |
530 | break; | |
531 | urk: | |
532 | default: | |
533 | error("First arg to divide neither a bignum nor int.",FALSE); | |
534 | } | |
535 | work = mynp->val; | |
536 | switch(TYPE(work)) { | |
537 | case INT: | |
538 | arg2 = (lispval) &dum2; | |
539 | dum2.I = work->i; | |
540 | dum2.CDR = (lispval) 0; | |
541 | break; | |
542 | case SDOT: | |
543 | arg2 = work; | |
544 | break; | |
545 | default: | |
546 | goto urk; | |
547 | } | |
548 | divbig(arg1,arg2, &quo, &rem); | |
549 | protect(quo); | |
550 | if(rem==((lispval)&dummy)) | |
551 | rem = inewint(dummy.I); | |
552 | protect(rem); | |
553 | protect(result = work = newdot()); | |
554 | work->d.car = quo; | |
555 | (work->d.cdr = newdot())->d.car = rem; | |
556 | Restorestack(); | |
557 | return(result); | |
558 | } | |
559 | ||
560 | lispval LEmuldiv(){ | |
561 | register struct argent * mynp = lbot+AD; | |
562 | register lispval work, result; | |
563 | int quo, rem; | |
564 | Savestack(3); /* fix register mask */ | |
565 | ||
566 | /* (Emuldiv mul1 mult2 add quo) => | |
567 | temp = mul1 + mul2 + sext(add); | |
568 | result = (list temp/quo temp%quo); | |
569 | to mix C and lisp a bit */ | |
570 | ||
571 | Imuldiv(mynp[0].val->i, mynp[1].val->i, mynp[2].val->i, | |
572 | mynp[3].val->i, &quo, &rem); | |
573 | protect(result=newdot()); | |
574 | (result->d.car=inewint(quo)); | |
575 | work = result->d.cdr = newdot(); | |
576 | (work->d.car=inewint(rem)); | |
577 | Restorestack(); | |
578 | return(result); | |
579 | } |