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: }

Defined functions

badfnsv defined in line 634; used 1 times
  • in line 55
ex_arg1 defined in line 324; used 2 times
ex_arg2 defined in line 336; used 2 times
ex_auto defined in line 354; used 2 times
ex_br defined in line 425; used 3 times
ex_br0 defined in line 418; used 2 times
ex_fdef defined in line 485; used 2 times
ex_fun defined in line 268; used 2 times
ex_ibr defined in line 469; used 2 times
ex_ibr0 defined in line 437; used 3 times
ex_nilret defined in line 535; used 5 times
ex_rest defined in line 365; used 2 times
ex_shell defined in line 604; used 1 times
funcomp defined in line 153; used 2 times
fundef defined in line 121; used 1 times
  • in line 74
funedit defined in line 15; used 2 times
funread defined in line 61; used 2 times
funwrite defined in line 77; used 2 times
reverse defined in line 542; used 1 times
sichk defined in line 592; used 5 times
tback defined in line 567; used 2 times

Defined variables

Sccsid defined in line 1; never used
atfrom defined in line 566; used 1 times
bad_fn defined in line 5; used 3 times
labcpe defined in line 151; used 1 times
labcpp defined in line 151; used 2 times
prolgerr defined in line 6; used 2 times

Defined macros

EXCH defined in line 549; used 1 times
Last modified: 1983-06-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4988
Valid CSS Valid XHTML 1.0 Strict