|
|
1.1 root 1: #ifndef lint
2: static char *rcsid =
3: "$Header: eval2.c,v 1.8 85/03/24 11:03:02 sklower Exp $";
4: #endif
5:
6: /* -[Sat May 7 23:38:37 1983 by jkf]-
7: * eval2.c $Locker: $
8: * more of the evaluator
9: *
10: * (c) copyright 1982, Regents of the University of California
11: */
12:
13:
14: #include "global.h"
15: #include "frame.h"
16:
17: /* Iarray - handle array call.
18: * fun - array object
19: * args - arguments to the array call , most likely subscripts.
20: * evalp - flag, if TRUE then the arguments should be evaluated when they
21: * are stacked.
22: */
23: lispval
24: Iarray(fun,args,evalp)
25: register lispval fun,args;
26: {
27: Savestack(2);
28:
29: lbot = np;
30: protect(fun->ar.accfun);
31: for ( ; args != nil ; args = args->d.cdr) /* stack subscripts */
32: if(evalp) protect(eval(args->d.car));
33: else protect(args->d.car);
34: protect(fun);
35: vtemp = Lfuncal();
36: Restorestack();
37: return(vtemp);
38: }
39:
40:
41: dumpmydata(thing)
42: int thing;
43: {
44: register int *ip = &thing;
45: register int *lim = ip + nargs();
46:
47: printf("Dumpdata got %d args:\n",nargs());
48: while(ip < lim) printf("%x\n",*ip++);
49: return(0);
50: }
51: /* Ifcall :: call foreign function/subroutine
52: * Ifcall is handed a binary object which is the function to call.
53: * This function has already been determined to be a foreign function
54: * by noticing that its discipline field is a string.
55: * The arguments to pass have already been evaluated and stacked. We
56: * create on the stack a 'callg' type argument list to give to the
57: * function. What is passed to the foreign function depends on the
58: * type of argument. Certain args are passes directly, others must be
59: * copied since the foreign function my want to change them.
60: * When the foreign function returns, we may have to box the result,
61: * depending on the type of foreign function.
62: */
63: lispval
64: Ifcall(a)
65: lispval a;
66: {
67: char *alloca();
68: long callg_();
69: register int *arglist;
70: register int index;
71: register struct argent *mynp;
72: register lispval ltemp;
73: pbuf pb;
74: int nargs = np - lbot, kind, mysize, *ap;
75: Keepxs();
76:
77: /* put a frame on the stack which will save np and lbot in a
78: easy to find place in a standard way */
79: errp = Pushframe(F_TO_FORT,nil,nil);
80: mynp = lbot;
81: kind = (((char *)a->bcd.discipline)[0]);
82:
83: /* dispatch according to whether call by reference or value semantics */
84: switch(kind) {
85: case 'f': case 'i': case 's': case 'r':
86: arglist = (int *) alloca((nargs + 1) * sizeof(int));
87: *arglist = nargs;
88: for(index = 1; index <= nargs; index++) {
89: switch(TYPE(ltemp=mynp->val)) {
90: /* fixnums and flonums must be reboxed */
91: case INT:
92: stack(0);
93: arglist[index] = (int) sp();
94: *(int *) arglist[index] = ltemp->i;
95: break;
96: case DOUB:
97: stack(0);
98: stack(0);
99: arglist[index] = (int) sp();
100: *(double *) arglist[index] = ltemp->r;
101: break;
102:
103: /* these cause only part of the structure to be sent */
104:
105: case ARRAY:
106: arglist[index] = (int) ltemp->ar.data;
107: break;
108:
109:
110: case BCD:
111: arglist[index] = (int) ltemp->bcd.start;
112: break;
113:
114: /* anything else should be sent directly */
115:
116: default:
117: arglist[index] = (int) ltemp;
118: break;
119: }
120: mynp++;
121: }
122: break;
123: case 'v':
124: while(TYPE(mynp->val)!=VECTORI)
125: mynp->val = error(
126: "First arg to c-function-returning-vector must be of type vector-immediate",
127: TRUE);
128: nargs--;
129: mynp++;
130: lbot++;
131: case 'c': case 'd':
132: /* make one pass over args
133: calculating size of arglist */
134: while(mynp < np) switch(TYPE(ltemp=mynp++->val)) {
135: case DOUB:
136: nargs += ((sizeof(double)/sizeof(int))-1);
137: break;
138: case VECTORI:
139: if(ltemp->v.vector[-1]==Vpbv) {
140: nargs += -1+VecTotSize(ltemp->vl.vectorl[-2]);
141: }
142: }
143: arglist = (int *) alloca((nargs+1)*sizeof(int));
144: *arglist = nargs;
145: ap = arglist + 1;
146: /* make another pass over the args
147: actually copying the arguments */
148: for(mynp = lbot; mynp < np; mynp++)
149: switch(TYPE(ltemp=mynp->val)) {
150: case INT:
151: *ap++ = ltemp->i;
152: break;
153: case DOUB:
154: *(double *)ap = ltemp->r;
155: ap += (sizeof (double)) / (sizeof (long));
156: break;
157: case VECTORI:
158: if(ltemp->v.vector[-1]==Vpbv) {
159: mysize = ltemp->vl.vectorl[-2];
160: mysize = sizeof(long) * VecTotSize(mysize);
161: xbcopy(ap,ltemp,mysize);
162: ap = (long *) (mysize + (int) ap);
163: break;
164: }
165: default:
166: *ap++ = (long) ltemp;
167: }
168: }
169: switch(kind) {
170: case 'i': /* integer-function */
171: case 'c': /* C-function */
172: ltemp = inewint(callg_(a->bcd.start,arglist));
173: break;
174:
175: case 'r': /* real-function*/
176: case 'd': /* C function declared returning double */
177: {
178: double result =
179: (* ((double (*)()) callg_))(a->bcd.start,arglist);
180: ltemp = newdoub();
181: ltemp->r = result;
182: }
183: break;
184:
185: case 'f': /* function */
186: ltemp = (lispval) callg_(a->bcd.start,arglist);
187: break;
188:
189: case 'v': /* C function returning a structure */
190: ap = (long *) callg_(a->bcd.start,arglist);
191: ltemp = (--lbot)->val;
192: mysize = ltemp->vl.vectorl[-2];
193: mysize = sizeof(long) * VecTotSize(mysize);
194: xbcopy(ltemp,ap,mysize);
195: break;
196:
197: default:
198: case 's': /* subroutine */
199: callg_(a->bcd.start,arglist);
200: ltemp = tatom;
201: }
202: errp = Popframe();
203: Freexs();
204: return(ltemp);
205: }
206:
207: xbcopy(to,from,size)
208: register char *to, *from;
209: register size;
210: {
211: while(--size >= 0) *to++ = *from++;
212: }
213:
214: lispval
215: ftolsp_(arg1)
216: lispval arg1;
217: {
218: int count;
219: register lispval *ap = &arg1;
220: lispval save;
221: pbuf pb;
222: Savestack(1);
223:
224: if((count = nargs())==0) return;;
225:
226: if(errp->class==F_TO_FORT)
227: np = errp->svnp;
228: errp = Pushframe(F_TO_LISP,nil,nil);
229: lbot = np;
230: for(; count > 0; count--)
231: np++->val = *ap++;
232: save = Lfuncal();
233: errp = Popframe();
234: Restorestack();
235: return(save);
236: }
237:
238: lispval
239: ftlspn_(func,arglist)
240: lispval func;
241: register long *arglist;
242: {
243: int count;
244: lispval save;
245: pbuf pb;
246: Savestack(1);
247:
248: if(errp->class==F_TO_FORT)
249: np = errp->svnp;
250: errp = Pushframe(F_TO_LISP,nil,nil);
251: lbot = np;
252: np++->val = func;
253: count = *arglist++;
254: for(; count > 0; count--)
255: np++->val = (lispval) (*arglist++);
256: save = Lfuncal();
257: errp = Popframe();
258: Restorestack();
259: return(save);
260: }
261:
262:
263:
264: /* Ifclosure :: evaluate a fclosure (new version)
265: * the argument clos is a vector whose property is the atom fclosure
266: * the form of the vector is
267: * 0: function to run
268: * then for each symbol there is on vector entry containing a
269: * pointer to a sequence of two list cells of this form:
270: * (name value . count)
271: * name is the symbol name to close over
272: * value is the saved value of the closure
273: * (if the closure is 'active', the current value will be in the
274: * symbol itself)
275: * count is a fixnum box (which can be destructively modified safely)
276: * it is normally 0. Each time the variable is put on the stack, it is
277: * incremented. It is decremented each time the the closure is left.
278: * If the closure is invoked recusively without a rebinding of the
279: * closure variable X, then the count will not be incremented.
280: *
281: * when entering a fclosure, for each variable there are three
282: * possibities:
283: * (a) this is the first instance of this closed variable
284: * (b) this is the second or greater recursive instance of
285: * this closure variable, however it hasn't been normally lambda
286: * bound since the last closure invocation
287: * (c) like (b) but it has been lambda bound before the most recent
288: * closure.
289: *
290: * case (a) can be determined by seeing if the count is 0.
291: * if the count is >0 then we must scan from the top of the stack down
292: * until we find either the closure or a lambda binding of the variable
293: * this determines whether it is case (b) or (c).
294: *
295: * There are three actions to perform in this routine:
296: * 1. determine the closure type (a,b or c) and do any binding necessary
297: * 2. call the closure function
298: * 3. unbind any necessary closure variables.
299: *
300: * Now, the details of those actions:
301: * 1. for case (b), do nothing as we are still working with the correct
302: * value
303: * for case (a), pushdown the symbol and give it the value from
304: * the closure, inc the closure count
305: * push a closure marker on the bindstack too.
306: * for case (c), must locate the correct value to set by searching
307: * for the last lambda binding before the previous closure.
308: * pushdown the symbol and that value, inc the closure count
309: * push a closure marker on the bindstack too.
310: * a closure marker has atom == int:closure-marker and value pointing
311: * to the closure list. This will be noticed when unbinding.
312: *
313: * 3. unbinding is just like popnames except if a closure marker is
314: * seen, then this must be done:
315: * if the count is 1, just store the symbol's value in the closure
316: * and decrement the count.
317: * if the count is >1, then search up the stack for the last
318: * lambda before the next occurance of this closure variable
319: * and set its value to the current value of the closure.
320: * decrement the closure count.
321: *
322: * clos is the fclosure, funcallp is TRUE if this is called from funcall,
323: * otherwise it is called from apply
324: */
325:
326: #define Case_A 0
327: #define Case_B 1
328: #define Case_C 2
329:
330: lispval
331: Ifclosure(clos,funcallp)
332: register lispval clos;
333: {
334: struct nament *oldbnp = bnp, *lbnp, *locatevar();
335: register int i;
336: register lispval vect;
337: int numvars, vlength, tcase, foundc;
338: lispval handy, atm_dtpr, value_dtpr, Ifuncal(), Lapply();
339: Savestack(3);
340:
341: /* bind variables to their values given in the fclosure */
342: vlength = VecTotSize(clos->vl.vectorl[VSizeOff]);
343: /* vector length must be positive (it has to have a function at least) */
344: if (vlength < 1)
345: errorh1(Vermisc,"funcall: fclosure has wrong size ",nil,FALSE,0, clos);
346:
347: numvars = (vlength - 1); /* number of varibles */
348:
349: for (i = 1 ; i < vlength ; i += 1)
350: {
351: atm_dtpr = clos->v.vector[i]; /* car is symbol name */
352: value_dtpr = atm_dtpr->d.cdr; /* car: value, cdr: fixnum count */
353:
354: if(value_dtpr->d.cdr->i == 0)
355: tcase = Case_A; /* first call */
356: else {
357: lbnp = locatevar(atm_dtpr,&foundc,bnp-1);
358: if (!foundc)
359: {
360: /* didn't find the expected closure, count must be
361: wrong, correct it and assume case (a)
362: */
363: tcase = Case_A;
364: value_dtpr->d.cdr->i = 0;
365: }
366: else if(lbnp) tcase = Case_C ; /* found intermediate lambda bnd*/
367: else tcase = Case_B; /* no intermediate lambda bind */
368: }
369:
370: /* now bind the value if necessary */
371: switch(tcase) {
372: case Case_A: PUSHDOWN(atm_dtpr->d.car,value_dtpr->d.car);
373: PUSHVAL(clos_marker,atm_dtpr);
374: value_dtpr->d.cdr->i += 1;
375: break;
376:
377: case Case_B: break; /* nothing to do */
378:
379: case Case_C: /* push first bound value after last close */
380: PUSHDOWN(atm_dtpr->d.car,lbnp->val);
381: PUSHVAL(clos_marker,atm_dtpr);
382: value_dtpr->d.cdr->i += 1;
383: break;
384: }
385: }
386:
387: if(funcallp)
388: handy = Ifuncal(clos->v.vector[0]);
389: else {
390: handy = lbot[-2].val; /* get args to apply. This is hacky and may
391: fail if apply is changed */
392: lbot = np;
393: protect(clos->v.vector[0]);
394: protect(handy);
395: handy = Lapply();
396: }
397:
398: xpopnames(oldbnp); /* pop names with consideration for closure markers */
399:
400: if(!funcallp) Restorestack();
401: return(handy);
402: }
403:
404: /* xpopnames :: pop values from bindstack, but look out for
405: * closure markers. This is used (instead of the faster popnames)
406: * when we know there will be closure markers or when we can't
407: * be sure that there won't be closure markers (eg. in non-local go's)
408: */
409: xpopnames(llimit)
410: register struct nament *llimit;
411: {
412: register struct nament *rnp, *lbnp;
413: lispval atm_dtpr, value_dtpr;
414: int foundc;
415:
416: for(rnp = bnp; --rnp >= llimit;)
417: {
418: if(rnp->atm == clos_marker)
419: {
420: atm_dtpr = rnp->val;
421: value_dtpr = atm_dtpr->d.cdr;
422: if(value_dtpr->d.cdr->i <= 1)
423: {
424: /* this is the only occurance of this closure variable
425: * just restore current value to this closure.
426: */
427: value_dtpr->d.car = atm_dtpr->d.car->a.clb;
428: }
429: else {
430: /* locate the last lambda before the next occurance of
431: * this closure and store the current symbol's value
432: * there
433: */
434: lbnp = locatevar(atm_dtpr,&foundc,rnp-2);
435: if(!foundc)
436: {
437: /* strange, there wasn't a closure to be found.
438: * well, we will fix things up so the count is
439: * right.
440: */
441: value_dtpr->d.car = atm_dtpr->d.car->a.clb;
442: value_dtpr->d.cdr->i = 1;
443: }
444: else if (lbnp) {
445: /* note how the closures value isn't necessarily
446: * stored in the closure, it may be stored on
447: * the bindstack
448: */
449: lbnp->val = atm_dtpr->d.car->a.clb;
450: }
451: /* the case where lbnp is 0 should never happen, but
452: if it does, we can just do nothing safely
453: */
454: }
455: value_dtpr->d.cdr->i -= 1;
456: } else rnp->atm->a.clb = rnp->val; /* the normal case */
457: }
458: bnp = llimit;
459: }
460:
461:
462: struct nament *
463: locatevar(clos,foundc,rnp)
464: struct nament *rnp;
465: lispval clos;
466: int *foundc;
467: {
468: register struct nament *retbnp;
469: lispval symb;
470:
471: retbnp = (struct nament *) 0;
472: *foundc = 0;
473:
474: symb = clos->d.car;
475:
476: for( ; rnp >= orgbnp ; rnp--)
477: {
478: if((rnp->atm == clos_marker) && (rnp->val == clos))
479: {
480: *foundc = 1; /* found the closure */
481: return(retbnp);
482: }
483: if(rnp->atm == symb) retbnp = rnp;
484: }
485: return(retbnp);
486: }
487:
488: lispval
489: LIfss()
490: {
491: register lispval atm_dtpr, value_dtpr;
492: struct nament *oldbnp = bnp, *lbnp;
493: int tcase, foundc = 0;
494: lispval newval;
495: int argc = 1;
496: Savestack(2);
497:
498: switch(np-lbot) {
499: case 2:
500: newval = np[-1].val;
501: argc++;
502: case 1:
503: atm_dtpr = lbot->val;
504: value_dtpr = atm_dtpr->d.cdr;
505: break;
506: default:
507: argerr("int:fclosure-symbol-stuff");
508: }
509: /* this code is copied from Ifclosure */
510:
511: if(value_dtpr->d.cdr->i==0)
512: tcase = Case_A; /* closure is not active */
513: else {
514: lbnp = locatevar(atm_dtpr,&foundc,bnp-1);
515: if (!foundc)
516: {
517: /* didn't find closure, count must be wrong,
518: correct it and assume case (a).*/
519: tcase = Case_A;
520: value_dtpr->d.cdr->i = 0;
521: }
522: else if(lbnp) tcase = Case_C; /* found intermediate lambda*/
523: else tcase = Case_B;
524: }
525:
526: switch(tcase) {
527: case Case_B:
528: if(argc==2) return(atm_dtpr->d.car->a.clb = newval);
529: return(atm_dtpr->d.car->a.clb);
530:
531: case Case_A:
532: if(argc==2) return(value_dtpr->d.car = newval);
533: return(value_dtpr->d.car);
534:
535: case Case_C:
536: if(argc==2) return(lbnp->val = newval);
537: return(lbnp->val);
538: }
539: /*NOTREACHED*/
540: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.