|
|
1.1 ! root 1: static char Sccsid[] = "ai.c @(#)ai.c 1.2 10/1/82 Berkeley "; ! 2: #include <signal.h> ! 3: #include "apl.h" ! 4: ! 5: char *bad_fn = "apl.badfn"; ! 6: int prolgerr; /* Flag -- set if bad fetch in prologue */ ! 7: ! 8: /* ! 9: * funedit -- edit a file and read it in. ! 10: * ! 11: * If the arg to funedit is non-zero, it is used as a ! 12: * pointer to the file name to be used. If it is zero, ! 13: * the namep of the function is used for the file name. ! 14: */ ! 15: funedit(fname, editor) ! 16: char *fname; ! 17: { ! 18: register struct item *p; ! 19: register f, (*a)(); ! 20: char *c; ! 21: extern edmagic; ! 22: ! 23: p = sp[-1]; ! 24: if(p->type != LV) ! 25: error("fed B"); ! 26: sichk(p); ! 27: if(fname == 0) ! 28: fname = ((struct nlist *)p)->namep; ! 29: a = signal(SIGINT, SIG_IGN); ! 30: f = FORKF(1); ! 31: if(f == 0) { ! 32: for(f=3; f<7; f++) ! 33: close(f); ! 34: c = (editor == DEL ? "/usr/bin/apldel" : "/usr/local/xed"); ! 35: execl(c+9, c+9, fname, "-f", apl_term ? "-A":"-a", "-p", edmagic ? "-r":0, 0); ! 36: execl(c+4, c+9, fname, "-f", apl_term ? "-A":"-a", "-p", edmagic ? "-r":0, 0); ! 37: execl(c, c+9, fname, "-f", apl_term ? "-A":"-a", "-p", edmagic ? "-r":0, 0); ! 38: printf("cannot find the editor!\n"); ! 39: exit(1); ! 40: } ! 41: if(f == -1) ! 42: error("try again"); ! 43: while(wait(0) != f) ! 44: ; ! 45: signal(SIGINT, a); ! 46: ! 47: /* Read function into workspace. If "funread" (which calls ! 48: * "fundef") returns 0, an error occurred in processing the ! 49: * header (line 0). If this happened with "editf" or "del", ! 50: * save the bad function in the file "bad_fn". ! 51: */ ! 52: ! 53: if (funread(fname) == 0 && fname == scr_file){ ! 54: unlink(bad_fn); ! 55: if (badfnsv(fname)) ! 56: printf("function saved in %s\n", bad_fn); ! 57: } ! 58: } ! 59: ! 60: ! 61: funread(fname) ! 62: char *fname; ! 63: { ! 64: register struct item *p; ! 65: register f, pid; ! 66: ! 67: p = sp[-1]; ! 68: sp--; ! 69: if(p->type != LV) ! 70: error("fnl B"); ! 71: if(fname == 0) ! 72: fname = ((struct nlist *)p)->namep; ! 73: f = opn(fname, 0); ! 74: return(fundef(f)); ! 75: } ! 76: ! 77: funwrite(fname) ! 78: char *fname; ! 79: { ! 80: register struct nlist *n; ! 81: register i, cnt; ! 82: int fd1, fd2; ! 83: char buf[512]; ! 84: ! 85: n = (struct nlist *)sp[-1]; ! 86: sp--; ! 87: if(n->type != LV) ! 88: error("fnwrite B"); ! 89: if(fname ==0) ! 90: fname = n->namep; ! 91: fd1 = opn(fname, 0644); ! 92: switch(n->use){ ! 93: default: ! 94: CLOSEF(fd1); ! 95: error("fnwrite T"); ! 96: ! 97: case 0: /* undefined fn */ ! 98: printf("\t[new fn]\n"); ! 99: break; /* empty file already created -- do nothing */ ! 100: ! 101: case NF: ! 102: case MF: ! 103: case DF: ! 104: fd2 = DUPF(wfile); ! 105: SEEKF(fd2, (long)n->label, 0); ! 106: do { ! 107: cnt = READF(fd2, buf, 512); ! 108: if(cnt <= 0) ! 109: error("fnwrite eof"); ! 110: for(i=0; i<cnt; i++) ! 111: if(buf[i] == 0) ! 112: break; ! 113: WRITEF(fd1, buf, i); ! 114: } while(i == 512); ! 115: CLOSEF(fd2); ! 116: break; ! 117: } ! 118: CLOSEF(fd1); ! 119: } ! 120: ! 121: fundef(f) ! 122: { ! 123: register a, c; ! 124: struct nlist *np; ! 125: char b[512]; ! 126: ! 127: ifile = f; ! 128: a = rline(0); ! 129: if(a == 0) ! 130: error("fnd eof"); ! 131: c = compile(a, 2); ! 132: free(a); ! 133: if(c == 0) ! 134: goto out; ! 135: copy(IN, c+1, &np, 1); ! 136: sichk(np); ! 137: erase(np); ! 138: np->use = ((struct chrstrct *)c)->c[0]; ! 139: np->label = SEEKF(wfile, 0L, 2); ! 140: SEEKF(ifile, 0L, 0); ! 141: while((a=READF(ifile, b, 512)) > 0) ! 142: WRITEF(wfile, b, a); ! 143: WRITEF(wfile, "", 1); ! 144: out: ! 145: CLOSEF(ifile); ! 146: ifile = 0; ! 147: return(c); ! 148: } ! 149: ! 150: data lnumb; ! 151: char *labcpp,*labcpe; ! 152: ! 153: funcomp(np) ! 154: struct nlist *np; ! 155: { ! 156: register char *a, *c; ! 157: register *p; ! 158: int i, err, size; ! 159: char labp[MAXLAB*20], labe[MAXLAB*4]; ! 160: ! 161: ifile = DUPF(wfile); ! 162: SEEKF(ifile, (long)np->label, 0); ! 163: size = 0; ! 164: err = 0; ! 165: ! 166: labgen = 0; ! 167: pass1: ! 168: a = rline(0); ! 169: if(a == 0) { ! 170: if(err) ! 171: goto out; ! 172: p = (int *)alloc((size+2)*SINT); ! 173: *p = size; ! 174: size = 0; ! 175: SEEKF(ifile, (long)np->label, 0); ! 176: err++; ! 177: labcpp = labp; ! 178: labcpe = labe; ! 179: labgen = 1; ! 180: goto pass2; ! 181: } ! 182: c = compile(a, size==0? 3: 5); ! 183: size++; ! 184: free(a); ! 185: if(c == 0) { ! 186: err++; ! 187: goto pass1; ! 188: } ! 189: free(c); ! 190: goto pass1; ! 191: ! 192: pass2: ! 193: a = rline(0); ! 194: if(a == 0) ! 195: goto pass3; ! 196: lnumb = size; ! 197: c = compile(a, size==0? 3: 5); ! 198: size++; ! 199: free(a); ! 200: if(c == 0) ! 201: goto out; ! 202: p[size] = c; ! 203: goto pass2; ! 204: ! 205: pass3: ! 206: labgen = 0; ! 207: SEEKF(ifile, (long)np->label, 0); ! 208: a = rline(0); ! 209: if(a == 0){ ! 210: err++; ! 211: goto out; ! 212: } ! 213: c = compile(a, 4); ! 214: free(a); ! 215: if(c == 0) ! 216: goto out; ! 217: if(labcpp != labp){ ! 218: reverse(labe); ! 219: p[size+1] = catcode(labe, c); ! 220: free(c); ! 221: /* ! 222: /* *** KLUDGE *** ! 223: /* ! 224: /* due to the "line-at-a-time" nature of the parser, ! 225: /* we have to screw around with the compiled strings. ! 226: /* ! 227: /* At this point, we have: ! 228: /* ! 229: /* fn-prologue (p[1]): <AUTOs and ARGs>, ELID, EOF ! 230: /* label-prologue (labp): <AUTOs and LABELs>, EOF ! 231: /* ! 232: /* and we want to produce: ! 233: /* ! 234: /* fn-prologue (p[1]): <AUTOs and ARGs>,<AUTOs and LABELs>, ELID, EOF. ! 235: */ ! 236: a = csize(p[1]) - 1; ! 237: c = csize(labp) - 1; ! 238: /* ! 239: * if there is an ELID at the end of the fn-prologue, ! 240: * move it to the end of the label-prologue. ! 241: */ ! 242: if (p[1]->c[(int)a-1] == ELID){ ! 243: p[1]->c[(int)a-1] = EOF; ! 244: labp[(int)c] = ELID; ! 245: labp[(int)c+1] = EOF; ! 246: } else ! 247: error("elid B"); ! 248: /* *** END KLUDGE *** */ ! 249: a = p[1]; ! 250: p[1] = catcode(a,labp); ! 251: free(a); ! 252: } else ! 253: p[size+1] = c; ! 254: if(debug) { ! 255: dump(p[1], 1); ! 256: dump(p[size+1], 1); ! 257: } ! 258: np->itemp = (struct item *)p; ! 259: err = 0; ! 260: ! 261: out: ! 262: CLOSEF(ifile); ! 263: ifile = 0; ! 264: if(err) ! 265: error("syntax"); ! 266: } ! 267: ! 268: ex_fun() ! 269: { ! 270: struct nlist *np; ! 271: register *p, s; ! 272: struct si si; ! 273: ! 274: pcp += copy(IN, pcp, &np, 1); ! 275: if (np->use < NF || np->use > DF) { ! 276: printf("%s: ", np->namep); ! 277: error("not a fn"); ! 278: } ! 279: if(np->itemp == 0) ! 280: funcomp(np); ! 281: p = (int *)np->itemp; ! 282: /* setup new state indicator */ ! 283: si.sip = gsip; ! 284: gsip = &si; ! 285: si.np = np; ! 286: si.oldsp = 0; /* we can add a more complicated version, later */ ! 287: si.oldpcp = pcp; ! 288: si.funlc = 0; ! 289: si.suspended = 0; ! 290: prolgerr = 0; /* Reset error flag */ ! 291: s = *p; ! 292: checksp(); ! 293: if(funtrace) ! 294: printf("\ntrace: fn %s entered: ", np->namep); ! 295: if (setjmp(si.env)) ! 296: goto reenter; ! 297: while(1){ ! 298: si.funlc++; ! 299: if(funtrace) ! 300: printf("\ntrace: fn %s[%d]: ", np->namep, si.funlc-1); ! 301: execute(p[si.funlc]); ! 302: if(si.funlc == 1){ ! 303: si.oldsp = sp; ! 304: if (prolgerr) ! 305: error(""); ! 306: } ! 307: if(intflg) ! 308: error("I"); ! 309: reenter: ! 310: if(si.funlc <= 0 || si.funlc >= s) { ! 311: si.funlc = 1; /* for pretty traceback */ ! 312: if(funtrace) ! 313: printf("\ntrace: fn %s exits ", np->namep); ! 314: execute(p[s+1]); ! 315: /* restore state indicator to previous state */ ! 316: gsip = si.sip; ! 317: pcp = si.oldpcp; ! 318: return; ! 319: } ! 320: pop(); ! 321: } ! 322: } ! 323: ! 324: ex_arg1() ! 325: { ! 326: register struct item *p; ! 327: struct nlist *np; ! 328: ! 329: pcp += copy(IN, pcp, &np, 1); ! 330: p = fetch1(); ! 331: sp[-1] = np->itemp; ! 332: np->itemp = p; ! 333: np->use = DA; ! 334: } ! 335: ! 336: ex_arg2() ! 337: { ! 338: register struct item *p1, *p2; ! 339: struct nlist *np1, *np2; ! 340: ! 341: pcp += copy(IN, pcp, &np2, 1); /* get first argument's name */ ! 342: pcp++; /* skip over ARG1 */ ! 343: pcp += copy(IN, pcp, &np1, 1); /* get second arg's name */ ! 344: p1 = fetch1(); /* get first expr to be bound to arg */ ! 345: p2 = fetch(sp[-2]); /* get second one */ ! 346: sp[-1] = np1->itemp; /* save old value of name on stack */ ! 347: sp[-2] = np2->itemp; /* save second */ ! 348: np1->itemp = p1; /* new arg1 binding */ ! 349: np2->itemp = p2; /* ditto arg2 */ ! 350: np1->use = DA; /* release safety catch */ ! 351: np2->use = DA; ! 352: } ! 353: ! 354: ex_auto() ! 355: { ! 356: struct nlist *np; ! 357: ! 358: pcp += copy(IN, pcp, &np, 1); ! 359: checksp(); ! 360: *sp++ = np->itemp; ! 361: np->itemp = 0; ! 362: np->use = 0; ! 363: } ! 364: ! 365: ex_rest() ! 366: { ! 367: register struct item *p; ! 368: struct nlist *np; ! 369: ! 370: p = sp[-1]; ! 371: /* ! 372: * the following is commented out because ! 373: * of an obscure bug in the parser, which is ! 374: * too difficult to correct right now. ! 375: * the bug is related to the way the ! 376: * "fn epilog" is compiled. To accomodate labels, ! 377: * it was kludged up to have the label restoration ! 378: * code added after the entire fn was parsed. A problem ! 379: * is that the generated code is like: ! 380: * ! 381: * "rest-lab1 rest-lab2 eol rval-result rest-arg1 ..." ! 382: * ! 383: * the "eol rval-result" pops off the previous result, and ! 384: * puts a "fetched" version of the returned value (result) ! 385: * onto the stack. The bug is that the "eol rval." should ! 386: * be output at the beginning of the fn epilog. ! 387: * The following two lines used to be a simple ! 388: * "p = fetch(p)", which is used to disallow ! 389: * a fn to return a LV, (by fetching it, it gets ! 390: * converted to a RVAL.) Since we later added ! 391: * code which returned stuff which could not be ! 392: * fetched (the DU, dummy datum, for example), ! 393: * this thing had to be eliminated. An earlier ! 394: * version only fetched LV's, but that was eliminated ! 395: * by adding the "RVAL" operator. The test below ! 396: * was made a botch, because no LV's should ever be ! 397: * passed back. However, for this to be true, the ! 398: * "eol" should be executed first, so that any possible ! 399: * LV's left around by the last line executed are ! 400: * discarded. Since we have some "rest"s in the epilog ! 401: * before the eol, the following test fails. ! 402: * I can't think of why it won't work properly as it ! 403: * is, but if I had the time, I'd fix it properly. ! 404: * --jjb ! 405: */ ! 406: /* if(p->type == LV) ! 407: error("rest B"); */ ! 408: pcp += copy(IN, pcp, &np, 1); ! 409: erase(np); ! 410: np->itemp = sp[-2]; ! 411: np->use = 0; ! 412: if(np->itemp) ! 413: np->use = DA; ! 414: sp--; ! 415: sp[-1] = p; ! 416: } ! 417: ! 418: ex_br0() ! 419: { ! 420: ! 421: gsip->funlc = 0; ! 422: ex_elid(); ! 423: } ! 424: ! 425: ex_br() ! 426: { ! 427: register struct item *p; ! 428: ! 429: p = fetch1(); ! 430: if(p->size == 0) ! 431: return; ! 432: gsip->funlc = fix(getdat(p)); ! 433: } ! 434: /* ! 435: * immediate niladic branch -- reset SI ! 436: */ ! 437: ex_ibr0() ! 438: { ! 439: register struct si *s; ! 440: register *p; ! 441: ! 442: s = gsip; ! 443: if(s == 0) ! 444: error("no suspended fn"); ! 445: if(s->suspended == 0) ! 446: error("imm } B1"); ! 447: gsip->suspended = 0; ! 448: while((s = gsip) && s->suspended == 0){ ! 449: if(s->oldsp == 0 || sp < s->oldsp) ! 450: error("imm } B2"); ! 451: while(sp > s->oldsp){ ! 452: pop(); ! 453: } ! 454: pop(); /* pop off possibly bad previous result */ ! 455: ex_nilret(); /* and stick on some dummy datum */ ! 456: p = (int *)s->np->itemp; ! 457: execute(p[*p + 1]); ! 458: gsip = s->sip; ! 459: } ! 460: if(gsip == 0) ! 461: while(sp > stack) ! 462: pop(); ! 463: } ! 464: ! 465: /* ! 466: * monadic immediate branch -- resume fn at specific line ! 467: */ ! 468: ! 469: ex_ibr() ! 470: { ! 471: register struct si *s; ! 472: if((s = gsip) == 0) ! 473: error("no suspended fn"); ! 474: ex_br(); ! 475: if(s->oldsp == 0 || sp < s->oldsp) ! 476: error("imm }n B"); ! 477: while(sp > s->oldsp){ ! 478: pop(); ! 479: } ! 480: pop(); /* pop off possibly bad previous result */ ! 481: ex_nilret(); /* and stick on some dummy datum */ ! 482: longjmp(s->env); /* warp out */ ! 483: } ! 484: ! 485: ex_fdef() ! 486: { ! 487: register struct item *p; ! 488: register char *p1, *p2; ! 489: struct nlist *np; ! 490: char b[512]; ! 491: int i, dim0, dim1; ! 492: ! 493: p = fetch1(); ! 494: if((p->rank != 2 && p->rank != 1) || p->type != CH) ! 495: error("Lfx D"); ! 496: ! 497: ! 498: /* The following code has been commented out as a ! 499: * test of slight modifications to the compiler. ! 500: * Before this change, it was impossible to use "Lfx" ! 501: * from inside an APL function, for it might damage ! 502: * an existing function by the same name. The compiler ! 503: * now checks when processing function headers to see ! 504: * if the function is suspended by calling "sichk", which ! 505: * will generate an error if so. Hopefully this will now ! 506: * allow "Lfx" to be used freely without disastrous side- ! 507: * effects. ! 508: */ ! 509: ! 510: /* if(gsip) ! 511: error("si damage -- type ')reset'"); */ ! 512: ! 513: dim0 = p->dim[0]; ! 514: dim1 = p->dim[1]; ! 515: if(p->rank == 1) ! 516: dim1 = dim0; ! 517: copy(CH, p->datap, b, dim1); ! 518: b[dim1] = '\n'; ! 519: ! 520: p2 = compile(b, 2); ! 521: if(p2 != 0){ ! 522: copy(IN, p2+1, &np, 1); ! 523: erase(np); ! 524: np->use = *p2; ! 525: free(p2); ! 526: ! 527: np->label = SEEKF(wfile, 0L, 2); ! 528: fappend(wfile, p); ! 529: WRITEF(wfile,"",1); ! 530: } ! 531: pop(); ! 532: *sp++ = newdat(DA, 1, 0); ! 533: } ! 534: ! 535: ex_nilret() ! 536: { ! 537: checksp(); ! 538: *sp++ = newdat(DU,0,0); /* put looser onto stack */ ! 539: /* (should be discarded) */ ! 540: } ! 541: ! 542: reverse(s) ! 543: char *s; ! 544: { ! 545: register char *p, *q; ! 546: register char c; ! 547: int j; ! 548: ! 549: #define EXCH(a,b) {c=a;a=b;b=c;} ! 550: ! 551: p = q = s; ! 552: while(*p != EOF) ! 553: p++; ! 554: p -= 1+sizeof(char *); ! 555: while(q < p){ ! 556: for(j=0; j<1+sizeof (char *); j++) ! 557: EXCH(p[j], q[j]); ! 558: q += j; ! 559: p -= j; ! 560: } ! 561: } ! 562: ! 563: /* ! 564: * produce trace back info ! 565: */ ! 566: char *atfrom[] = {"at\t", "from\t", "", ""}; ! 567: tback(flag) ! 568: { ! 569: register struct si *p; ! 570: register i; ! 571: ! 572: p = gsip; ! 573: i = 0; ! 574: if(flag) ! 575: i = 2; ! 576: while(p){ ! 577: if(flag==0 && p->suspended) ! 578: return; ! 579: if (p->funlc != 1 || i){ /* skip if at line 0 */ ! 580: printf("%s%s[%d]%s\n", ! 581: atfrom[i], ! 582: p->np->namep, ! 583: p->funlc - 1, ! 584: (p->suspended ? " *" : "") ! 585: ); ! 586: i |= 1; ! 587: } ! 588: p = p->sip; ! 589: } ! 590: } ! 591: ! 592: sichk(n) ! 593: struct nlist *n; ! 594: { ! 595: register struct si *p; ! 596: ! 597: p = gsip; ! 598: while(p){ ! 599: if(n == p->np) ! 600: error("si damage -- type ')reset'"); ! 601: p = p->sip; ! 602: } ! 603: } ! 604: ex_shell(){ ! 605: ! 606: /* If the environment variable SHELL is defined, attempt to ! 607: * execute that shell. If not, or if that exec fails, attempt ! 608: * to execute the standard shell, /bin/sh ! 609: */ ! 610: ! 611: int (*addr)(), (*addr2)(); ! 612: char *getenv(); ! 613: register char *sh; ! 614: register i; ! 615: ! 616: addr = signal(SIGINT, SIG_IGN); ! 617: addr2 = signal(SIGQUIT, SIG_IGN); ! 618: i = FORKF(1); ! 619: if (i == 0){ ! 620: for(i=3; i<20; i++) close(i); ! 621: signal(SIGINT, SIG_DFL); ! 622: signal(SIGQUIT, SIG_DFL); ! 623: if (sh=getenv("SHELL")) ! 624: execl(sh, sh, 0); ! 625: execl("/bin/sh", "sh", 0); ! 626: printf("no shell!\n"); ! 627: exit(1); ! 628: } ! 629: if (i == -1) error("try again"); ! 630: while(wait(0) != i); ! 631: signal(SIGINT, addr); ! 632: signal(SIGQUIT, addr2); ! 633: } ! 634: badfnsv(fname) ! 635: char *fname; ! 636: { ! 637: ! 638: /* This routine saves the contents of "fname" in the file ! 639: * named in "bad_fn". It is called by "funedit" if the ! 640: * header of a function just read in is messed up (thus, ! 641: * the entire file is not lost). Returns 1 if successful, ! 642: * 0 if not. ! 643: */ ! 644: ! 645: register fd1, fd2, len; ! 646: char buf[512]; ! 647: ! 648: if ((fd1=OPENF(fname, 0)) < 0 || (fd2=CREATF(bad_fn, 0644)) < 0) ! 649: return(0); ! 650: while((len=READF(fd1, buf, 512)) > 0) ! 651: WRITEF(fd2, buf, len); ! 652: CLOSEF(fd1); ! 653: CLOSEF(fd2); ! 654: return(1); ! 655: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.