|
|
1.1 ! root 1: #ifndef lint ! 2: static char *rcsid = ! 3: "$Header: eval2.c,v 1.6 83/09/12 14:18: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: bcopy(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: bcopy(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: bcopy(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: ! 239: ! 240: /* Ifclosure :: evaluate a fclosure (new version) ! 241: * the argument clos is a vector whose property is the atom fclosure ! 242: * the form of the vector is ! 243: * 0: function to run ! 244: * then for each symbol there is on vector entry containing a ! 245: * pointer to a sequence of two list cells of this form: ! 246: * (name value . count) ! 247: * name is the symbol name to close over ! 248: * value is the saved value of the closure ! 249: * (if the closure is 'active', the current value will be in the ! 250: * symbol itself) ! 251: * count is a fixnum box (which can be destructively modified safely) ! 252: * it is normally 0. Each time the variable is put on the stack, it is ! 253: * incremented. It is decremented each time the the closure is left. ! 254: * If the closure is invoked recusively without a rebinding of the ! 255: * closure variable X, then the count will not be incremented. ! 256: * ! 257: * when entering a fclosure, for each variable there are three ! 258: * possibities: ! 259: * (a) this is the first instance of this closed variable ! 260: * (b) this is the second or greater recursive instance of ! 261: * this closure variable, however it hasn't been normally lambda ! 262: * bound since the last closure invocation ! 263: * (c) like (b) but it has been lambda bound before the most recent ! 264: * closure. ! 265: * ! 266: * case (a) can be determined by seeing if the count is 0. ! 267: * if the count is >0 then we must scan from the top of the stack down ! 268: * until we find either the closure or a lambda binding of the variable ! 269: * this determines whether it is case (b) or (c). ! 270: * ! 271: * There are three actions to perform in this routine: ! 272: * 1. determine the closure type (a,b or c) and do any binding necessary ! 273: * 2. call the closure function ! 274: * 3. unbind any necessary closure variables. ! 275: * ! 276: * Now, the details of those actions: ! 277: * 1. for case (b), do nothing as we are still working with the correct ! 278: * value ! 279: * for case (a), pushdown the symbol and give it the value from ! 280: * the closure, inc the closure count ! 281: * push a closure marker on the bindstack too. ! 282: * for case (c), must locate the correct value to set by searching ! 283: * for the last lambda binding before the previous closure. ! 284: * pushdown the symbol and that value, inc the closure count ! 285: * push a closure marker on the bindstack too. ! 286: * a closure marker has atom == int:closure-marker and value pointing ! 287: * to the closure list. This will be noticed when unbinding. ! 288: * ! 289: * 3. unbinding is just like popnames except if a closure marker is ! 290: * seen, then this must be done: ! 291: * if the count is 1, just store the symbol's value in the closure ! 292: * and decrement the count. ! 293: * if the count is >1, then search up the stack for the last ! 294: * lambda before the next occurance of this closure variable ! 295: * and set its value to the current value of the closure. ! 296: * decrement the closure count. ! 297: * ! 298: * clos is the fclosure, funcallp is TRUE if this is called from funcall, ! 299: * otherwise it is called from apply ! 300: */ ! 301: ! 302: #define Case_A 0 ! 303: #define Case_B 1 ! 304: #define Case_C 2 ! 305: ! 306: lispval ! 307: Ifclosure(clos,funcallp) ! 308: register lispval clos; ! 309: { ! 310: struct nament *oldbnp = bnp, *lbnp, *locatevar(); ! 311: register int i; ! 312: register lispval vect; ! 313: int numvars, vlength, tcase, foundc; ! 314: lispval handy, atm_dtpr, value_dtpr, Ifuncal(), Lapply(); ! 315: Savestack(3); ! 316: ! 317: /* bind variables to their values given in the fclosure */ ! 318: vlength = VecTotSize(clos->vl.vectorl[VSizeOff]); ! 319: /* vector length must be positive (it has to have a function at least) */ ! 320: if (vlength < 1) ! 321: errorh1(Vermisc,"funcall: fclosure has wrong size ",nil,FALSE,0, clos); ! 322: ! 323: numvars = (vlength - 1); /* number of varibles */ ! 324: ! 325: for (i = 1 ; i < vlength ; i += 1) ! 326: { ! 327: atm_dtpr = clos->v.vector[i]; /* car is symbol name */ ! 328: value_dtpr = atm_dtpr->d.cdr; /* car: value, cdr: fixnum count */ ! 329: ! 330: if(value_dtpr->d.cdr->i == 0) ! 331: tcase = Case_A; /* first call */ ! 332: else { ! 333: lbnp = locatevar(atm_dtpr,&foundc,bnp-1); ! 334: if (!foundc) ! 335: { ! 336: /* didn't find the expected closure, count must be ! 337: wrong, correct it and assume case (a) ! 338: */ ! 339: tcase = Case_A; ! 340: value_dtpr->d.cdr->i = 0; ! 341: } ! 342: else if(lbnp) tcase = Case_C ; /* found intermediate lambda bnd*/ ! 343: else tcase = Case_B; /* no intermediate lambda bind */ ! 344: } ! 345: ! 346: /* now bind the value if necessary */ ! 347: switch(tcase) { ! 348: case Case_A: PUSHDOWN(atm_dtpr->d.car,value_dtpr->d.car); ! 349: PUSHVAL(clos_marker,atm_dtpr); ! 350: value_dtpr->d.cdr->i += 1; ! 351: break; ! 352: ! 353: case Case_B: break; /* nothing to do */ ! 354: ! 355: case Case_C: /* push first bound value after last close */ ! 356: PUSHDOWN(atm_dtpr->d.car,lbnp->val); ! 357: PUSHVAL(clos_marker,atm_dtpr); ! 358: value_dtpr->d.cdr->i += 1; ! 359: break; ! 360: } ! 361: } ! 362: ! 363: if(funcallp) ! 364: handy = Ifuncal(clos->v.vector[0]); ! 365: else { ! 366: handy = lbot[-2].val; /* get args to apply. This is hacky and may ! 367: fail if apply is changed */ ! 368: lbot = np; ! 369: protect(clos->v.vector[0]); ! 370: protect(handy); ! 371: handy = Lapply(); ! 372: } ! 373: ! 374: xpopnames(oldbnp); /* pop names with consideration for closure markers */ ! 375: ! 376: if(!funcallp) Restorestack(); ! 377: return(handy); ! 378: } ! 379: ! 380: /* xpopnames :: pop values from bindstack, but look out for ! 381: * closure markers. This is used (instead of the faster popnames) ! 382: * when we know there will be closure markers or when we can't ! 383: * be sure that there won't be closure markers (eg. in non-local go's) ! 384: */ ! 385: xpopnames(llimit) ! 386: register struct nament *llimit; ! 387: { ! 388: register struct nament *rnp, *lbnp; ! 389: lispval atm_dtpr, value_dtpr; ! 390: int foundc; ! 391: ! 392: for(rnp = bnp; --rnp >= llimit;) ! 393: { ! 394: if(rnp->atm == clos_marker) ! 395: { ! 396: atm_dtpr = rnp->val; ! 397: value_dtpr = atm_dtpr->d.cdr; ! 398: if(value_dtpr->d.cdr->i <= 1) ! 399: { ! 400: /* this is the only occurance of this closure variable ! 401: * just restore current value to this closure. ! 402: */ ! 403: value_dtpr->d.car = atm_dtpr->d.car->a.clb; ! 404: } ! 405: else { ! 406: /* locate the last lambda before the next occurance of ! 407: * this closure and store the current symbol's value ! 408: * there ! 409: */ ! 410: lbnp = locatevar(atm_dtpr,&foundc,rnp-2); ! 411: if(!foundc) ! 412: { ! 413: /* strange, there wasn't a closure to be found. ! 414: * well, we will fix things up so the count is ! 415: * right. ! 416: */ ! 417: value_dtpr->d.car = atm_dtpr->d.car->a.clb; ! 418: value_dtpr->d.cdr->i = 1; ! 419: } ! 420: else if (lbnp) { ! 421: /* note how the closures value isn't necessarily ! 422: * stored in the closure, it may be stored on ! 423: * the bindstack ! 424: */ ! 425: lbnp->val = atm_dtpr->d.car->a.clb; ! 426: } ! 427: /* the case where lbnp is 0 should never happen, but ! 428: if it does, we can just do nothing safely ! 429: */ ! 430: } ! 431: value_dtpr->d.cdr->i -= 1; ! 432: } else rnp->atm->a.clb = rnp->val; /* the normal case */ ! 433: } ! 434: bnp = llimit; ! 435: } ! 436: ! 437: ! 438: struct nament * ! 439: locatevar(clos,foundc,rnp) ! 440: struct nament *rnp; ! 441: lispval clos; ! 442: int *foundc; ! 443: { ! 444: register struct nament *retbnp; ! 445: lispval symb; ! 446: ! 447: retbnp = (struct nament *) 0; ! 448: *foundc = 0; ! 449: ! 450: symb = clos->d.car; ! 451: ! 452: for( ; rnp >= orgbnp ; rnp--) ! 453: { ! 454: if((rnp->atm == clos_marker) && (rnp->val == clos)) ! 455: { ! 456: *foundc = 1; /* found the closure */ ! 457: return(retbnp); ! 458: } ! 459: if(rnp->atm == symb) retbnp = rnp; ! 460: } ! 461: return(retbnp); ! 462: } ! 463: ! 464: lispval ! 465: LIfss() ! 466: { ! 467: register lispval atm_dtpr, value_dtpr; ! 468: struct nament *oldbnp = bnp, *lbnp; ! 469: int tcase, foundc = 0; ! 470: lispval newval; ! 471: int argc = 1; ! 472: Savestack(2); ! 473: ! 474: switch(np-lbot) { ! 475: case 2: ! 476: newval = np[-1].val; ! 477: argc++; ! 478: case 1: ! 479: atm_dtpr = lbot->val; ! 480: value_dtpr = atm_dtpr->d.cdr; ! 481: break; ! 482: default: ! 483: argerr("int:fclosure-symbol-stuff"); ! 484: } ! 485: /* this code is copied from Ifclosure */ ! 486: ! 487: if(value_dtpr->d.cdr->i==0) ! 488: tcase = Case_A; /* closure is not active */ ! 489: else { ! 490: lbnp = locatevar(atm_dtpr,&foundc,bnp-1); ! 491: if (!foundc) ! 492: { ! 493: /* didn't find closure, count must be wrong, ! 494: correct it and assume case (a).*/ ! 495: tcase = Case_A; ! 496: value_dtpr->d.cdr->i = 0; ! 497: } ! 498: else if(lbnp) tcase = Case_C; /* found intermediate lambda*/ ! 499: else tcase = Case_B; ! 500: } ! 501: ! 502: switch(tcase) { ! 503: case Case_B: ! 504: if(argc==2) return(atm_dtpr->d.car->a.clb = newval); ! 505: return(atm_dtpr->d.car->a.clb); ! 506: ! 507: case Case_A: ! 508: if(argc==2) return(value_dtpr->d.car = newval); ! 509: return(value_dtpr->d.car); ! 510: ! 511: case Case_C: ! 512: if(argc==2) return(lbnp->val = newval); ! 513: return(lbnp->val); ! 514: } ! 515: /*NOTREACHED*/ ! 516: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.