|
|
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.