|
|
1.1 root 1: static char Sccsid[] = "a0.c @(#)a0.c 1.5 6/16/87 Berkeley ";
2: #include <signal.h>
3: #include "apl.h"
4: #include <math.h>
5: int chartab[];
6: int mkcore = 0; /* produce core image upon fatal error */
7: int edmagic = 0; /* turn on "ed" magic characters */
8:
9: main(argc, argp)
10: char **argp;
11: {
12: register char *p;
13: register a, b;
14: int c;
15: int fflag;
16: int intr(), intprws();
17: struct tm *localtime();
18: extern headline[];
19: #ifdef NBUF
20: struct iobuf iobf[NBUF]; /* Actual buffers */
21: #endif
22:
23: time(&stime);
24: /*
25: * kludge to force use of file descriptor in time part
26: * of C library; otherwise sbrks are going to die.
27: */
28: (void)localtime(&stime);
29: #ifdef NBUF
30: iobuf = iobf; /* Set up buffer pointer */
31: initbuf(); /* Set up to run */
32: #endif
33: /*
34: * setup scratch files
35: */
36: a = getpid();
37: scr_file = "/tmp/apled.000000";
38: ws_file = "/tmp/aplws.000000";
39: for(c=16; c > 10; c--){
40: b = '0' + a%10;
41: scr_file[c] = b;
42: ws_file[c] = b;
43: a /= 10;
44: }
45: offexit = isatty(0);
46: echoflg = !offexit;
47: a = 1; /* catch signals */
48:
49: /* Check to see if argp[0] is "prws". If so, set prwsflg */
50:
51: for(p=argp[0]; *p; p++);
52: while(p > argp[0] && *p != '/') p--;
53: if (*p == '/') p++;
54: for(c=0; c < 4; c++)
55: if (!p[c] || p[c] != "prws"[c])
56: goto notprws;
57: prwsflg = 1;
58: CLOSEF(0);
59: notprws:
60:
61: /* other flags... */
62:
63: while(argc > 1 && argp[1][0] == '-'){
64: argc--;
65: argp++;
66: while(*++*argp) switch(**argp){
67: case 'e': echoflg = 1; break;
68: case 'q': echoflg = 0; break;
69: case 'd':
70: case 'D': a = 0;
71: case 'c':
72: case 'C': mkcore = 1; break;
73: case 't': scr_file += 5;
74: ws_file += 5;
75: case 'm': apl_term = 1; break;
76: case 'r': edmagic = 1; break;
77: case 'o': offexit = 0; break;
78: }
79: }
80:
81: if (prwsflg)
82: echoflg = mkcore = a = 0; /* "prws" settings */
83:
84: thread.iorg = 1;
85: srand(thread.rl = 1);
86: thread.width = 72;
87: thread.digits = 9;
88: thread.fuzz = 1.0e-13;
89:
90: aplmod(1); /* Turn on APL mode */
91: if (a)
92: catchsigs();
93: if (prwsflg)
94: signal(SIGINT, intprws);
95: else
96: fppinit();
97:
98: /*
99: * open ws file
100: */
101:
102: CLOSEF(opn(WSFILE,0600));
103: wfile = opn(WSFILE,2);
104: zero = 0;
105: one = 1;
106: maxexp = 88;
107: pi = 3.141592653589793238462643383;
108:
109: sp = stack;
110: fflag = 1;
111: if (!prwsflg){
112: if((unsigned)signal(SIGINT, intr) & 01)
113: signal(SIGINT, 1);
114: printf(headline);
115: }
116: setexit();
117: if(fflag) {
118: fflag = 0;
119: if(argc > 1 && (a = opn(argp[1], 0)) > 0){
120: wsload(a);
121: printf(" %s\n", argp[1]);
122: CLOSEF(a);
123: } else {
124: if((a=OPENF("continue",0)) < 0) {
125: printf("clear ws\n");
126: } else {
127: wsload(a);
128: printf(" continue\n");
129: CLOSEF(a);
130: }
131: }
132: if (prwsflg){
133: ex_prws();
134: term(0);
135: }
136: evLlx(); /* eval latent expr, if any */
137: }
138: mainloop();
139: }
140:
141: mainloop()
142: {
143: register char *a, *comp;
144: static eotcount = MAXEOT; /* maximum eot's on input */
145:
146: setexit();
147: while(1){
148: if(echoflg)
149: echoflg = 1; /* enabled echo echo suppress off */
150: checksp();
151: if(intflg)
152: error("I");
153: putchar('\t');
154: a = rline(8);
155: if(a == 0) {
156: offexit &= isatty(0);
157: if (offexit) {
158: if (eotcount-- > 0)
159: printf("\ruse \')off\' to exit\n");
160: else
161: panic(0);
162: continue;
163: } else
164: term(0); /* close down and exit */
165: }
166: comp = compile(a, 0);
167: free(a);
168: if(comp == 0)
169: continue;
170: execute(comp);
171: free(comp);
172: /* note that if the execute errors out, then
173: * the allocated space pointed to by comp is never
174: * freed. This is hard to fix.
175: */
176: }
177: }
178:
179: intr()
180: {
181:
182: intflg = 1;
183: signal(SIGINT, intr);
184: SEEKF(0, 0L, 2);
185: }
186:
187: intprws()
188: {
189: /* "prws" interrupt -- restore old tty modes and exit */
190:
191: term(0177);
192: }
193:
194: char *
195: rline(s)
196: {
197: int rlcmp();
198: char line[CANBS];
199: register char *p;
200: register c, col;
201: char *cp, *retval;
202: char *dp;
203: int i,j;
204:
205: column = 0;
206: col = s;
207: p = line;
208: loop:
209: c = getchar();
210: if(intflg)
211: error("I");
212: switch(c) {
213:
214: case '\0':
215: case -1:
216: return(0);
217:
218: case '\b':
219: if(col)
220: col--;
221: goto loop;
222:
223: case '\t':
224: col = (col+8) & ~7;
225: goto loop;
226:
227: case ' ':
228: col++;
229: goto loop;
230:
231: case '\r':
232: col = 0;
233: goto loop;
234:
235: default:
236: if (p >= line+CANBS-2 || col > 127)
237: error("line too long");
238: *p++ = col;
239: *p++ = c; /* was and'ed with 0177... */
240: col++;
241: goto loop;
242:
243: case '\n':
244: ;
245: }
246: qsort(line, (p-line)/2, 2, rlcmp);
247: c = p[-2];
248: if(p == line)
249: c = 1; /* check for blank line */
250: *p = -1;
251: col = -1;
252: cp = (retval=alloc(c+3)) - 1;
253: for(p=line; p[0] != -1; p+=2) {
254: while(++col != p[0])
255: *++cp = ' ';
256: *++cp = p[1];
257: while(p[2] == col) {
258: if(p[3] != *cp) {
259: i = *cp ;
260: *cp = p[3];
261: break;
262: }
263: p += 2;
264: }
265: if(p[2] != col) continue;
266: while(p[2] == col) {
267: if(p[3] != *cp)
268: goto yuck;
269: p += 2;
270: }
271: #ifdef vax
272: i = ((i<<8) | *cp)&0177777;
273: #else
274: i |= *cp << 8;
275: #endif
276: for(j=0; chartab[j]; j++){
277: if(i == chartab[j]) {
278: *cp = j | 0200;
279: j = 0;
280: break;
281: }
282: }
283: if(j) {
284: yuck:
285: *cp = '\n';
286: pline(cp,++col);
287: error("Y error");
288: }
289: }
290: *++cp = '\n';
291: return(retval);
292: }
293:
294: rlcmp(a, b)
295: char *a, *b;
296: {
297: register c;
298:
299: if(c = a[0] - b[0])
300: return(c);
301: return(a[1] - b[1]);
302: }
303:
304: pline(str, loc)
305: char *str;
306: {
307: register c, l, col;
308:
309: col = 0;
310: l = 0;
311: do {
312: c = *str++;
313: l++;
314: if(l == loc)
315: col = column;
316: putchar(c);
317: } while(c != '\n');
318: if(col) {
319: putto(col);
320: putchar('^');
321: putchar('\n');
322: }
323: }
324:
325: putto(col)
326: {
327: while(col > column+8)
328: putchar('\t');
329: while(col > column)
330: putchar(' ');
331: }
332:
333: term(s)
334: {
335:
336: register j;
337:
338: unlink(WSFILE);
339: unlink(scr_file);
340: putchar('\n');
341: aplmod(0); /* turn off APL mode */
342: for(j=0; j<NFDS; j++) /* Close files */
343: CLOSEF(j);
344: exit(s);
345: }
346:
347: fix(d)
348: data d;
349: {
350: register i;
351:
352: i = floor(d+0.5);
353: return(i);
354: }
355:
356: fuzz(d1, d2)
357: data d1, d2;
358: {
359: double f1, f2;
360:
361: f1 = d1;
362: if(f1 < 0.)
363: f1 = -f1;
364: f2 = d2;
365: if(f2 < 0.)
366: f2 = -f2;
367: if(f2 > f1)
368: f1 = f2;
369: f1 *= thread.fuzz;
370: if(d1 > d2) {
371: if(d2+f1 >= d1)
372: return(0);
373: return(1);
374: }
375: if(d1+f1 >= d2)
376: return(0);
377: return(-1);
378: }
379:
380: pop()
381: {
382:
383: if(sp <= stack)
384: error("pop B");
385: dealloc(*--sp);
386: }
387:
388: erase(np)
389: struct nlist *np;
390: {
391: register *p;
392:
393: p = np->itemp;
394: if(p) {
395: switch(np->use) {
396: case NF:
397: case MF:
398: case DF:
399: for(; *p>0; (*p)--)
400: free(p[*p]);
401:
402: }
403: free(p);
404: np->itemp = 0;
405: }
406: np->use = 0;
407: }
408:
409: dealloc(p)
410: struct item *p;
411: {
412:
413: switch(p->type) {
414: default:
415: printf("[dealloc botch: %d]\n", p->type);
416: return;
417: case LBL:
418: ((struct nlist *)p)->use = 0; /* delete label */
419: case LV:
420: return;
421:
422: case DA:
423: case CH:
424: case QQ:
425: case QD:
426: case QC:
427: case EL:
428: case DU:
429: case QX:
430: free(p);
431: }
432: }
433:
434: struct item *
435: newdat(type, rank, size)
436: {
437: register i;
438: register struct item *p;
439:
440: /* Allocate a new data item. I have searched the specifications
441: * for C and as far as I can tell, it should be legal to
442: * declare a zero-length array inside a structure. However,
443: * the VAX C compiler (which I think is a derivative of the
444: * portable C compiler) does not allow this. The Ritchie
445: * V7 PDP-11 compiler does. I have redeclared "dim" to
446: * contain MRANK elements. When the data is allocated,
447: * space is only allocated for as many dimensions as there
448: * actually are. Thus, if there are 0 dimensions, no space
449: * will be allocated for "dim". This had better make the
450: * VAX happy, since it has sure made me unhappy.
451: *
452: * --John Bruner
453: */
454:
455:
456: if(rank > MRANK)
457: error("max R");
458: i = sizeof *p - SINT * (MRANK-rank);
459: if(type == DA)
460: i += size * SDAT; else
461: if(type == CH)
462: i += size;
463: p = alloc(i);
464: p->rank = rank;
465: p->type = type;
466: p->size = size;
467: p->index = 0;
468: if(rank == 1)
469: p->dim[0] = size;
470: p->datap = (data *)&p->dim[rank];
471: return(p);
472: }
473:
474: struct item *
475: dupdat(ap)
476: struct item *ap;
477: {
478: register struct item *p1, *p2;
479: register i;
480:
481: p1 = ap;
482: p2 = newdat(p1->type, p1->rank, p1->size);
483: for(i=0; i<p1->rank; i++)
484: p2->dim[i] = p1->dim[i];
485: copy(p1->type, p1->datap, p2->datap, p1->size);
486: return(p2);
487: }
488:
489: copy(type, from, to, size)
490: char *from, *to;
491: {
492: register i;
493: register char *a, *b;
494: int s;
495:
496: if((i = size) == 0)
497: return(0);
498: a = from;
499: b = to;
500: if(type == DA)
501: i *= SDAT; else
502: if(type == IN)
503: i *= SINT;
504: s = i;
505: do
506: *b++ = *a++;
507: while(--i);
508: return(s);
509: }
510:
511: struct item *
512: fetch1()
513: {
514: register struct item *p;
515:
516: p = fetch(sp[-1]);
517: sp[-1] = p;
518: return(p);
519: }
520:
521: struct item *
522: fetch2()
523: {
524: register struct item *p;
525:
526: sp[-2] = fetch(sp[-2]);
527: p = fetch(sp[-1]);
528: sp[-1] = p;
529: return(p);
530: }
531:
532: struct item *
533: fetch(ip)
534: struct item *ip;
535: {
536: register struct item *p, *q;
537: register i;
538: struct nlist *n;
539: int c;
540: struct chrstrct *cc;
541: extern prolgerr;
542:
543: p = ip;
544:
545: loop:
546: switch(p->type) {
547:
548: case QX:
549: free(p);
550: n = nlook("Llx");
551: if(n){
552: q = n->itemp;
553: p = dupdat(q);
554: copy(q->type, q->datap, p->datap, q->size);
555: } else
556: p = newdat(CH, 1, 0);
557: goto loop;
558:
559: case QQ:
560: free(p);
561: cc = rline(0);
562: if(cc == 0)
563: error("eof");
564: for(i=0; cc->c[i] != '\n'; i++)
565: ;
566: p = newdat(CH, 1, i);
567: copy(CH, cc, p->datap, i);
568: goto loop;
569:
570: case QD:
571: case QC:
572: printf("L:\n\t");
573: i = rline(8);
574: if(i == 0)
575: error("eof");
576: c = compile(i, 1);
577: free(i);
578: if(c == 0)
579: goto loop;
580: i = pcp;
581: execute(c);
582: pcp = i;
583: free(c);
584: free(p);
585: p = *--sp;
586: goto loop;
587:
588: case DU:
589: if(lastop != PRINT)
590: error("no fn result");
591:
592: case DA:
593: case CH:
594: p->index = 0;
595: return(p);
596:
597: case LV:
598:
599: /* KLUDGE --
600: *
601: * Currently, if something prevents APL from completing
602: * execution of line 0 of a function, it leaves with
603: * the stack in an unknown state and "gsip->oldsp" is
604: * zero. This is nasty because there is no way to
605: * reset out of it. The principle cause of error
606: * exits from line 0 is the fetch of an undefined
607: * function argument. The following code attempts
608: * to fix this by setting an error flag and creating
609: * a dummy variable for the stack if "used before set"
610: * occurs in the function header. "ex_fun" then will
611: * note that the flag is high and cause an error exit
612: * AFTER all header processing has been completed.
613: */
614:
615: if(((struct nlist *)p)->use != DA){
616: printf("%s: used before set",
617: ((struct nlist *)ip)->namep);
618: if ((!gsip) || gsip->funlc != 1)
619: error("");
620: q = newdat(DA, 0, 1); /* Dummy */
621: q->datap[0] = 0;
622: prolgerr = 1; /* ERROR flag */
623: return(q);
624: }
625: p = ((struct nlist *)p)->itemp;
626: i = p->type;
627: if(i == LBL)
628: i = DA; /* treat label as data */
629: q = newdat(i, p->rank, p->size);
630: copy(IN, p->dim, q->dim, p->rank);
631: copy(i, p->datap, q->datap, p->size);
632: return(q);
633:
634: default:
635: error("fetch B");
636: }
637: }
638:
639: topfix()
640: {
641: register struct item *p;
642: register i;
643:
644: p = fetch1();
645: if(p->type != DA || p->size != 1)
646: error("topval C");
647: i = fix(p->datap[0]);
648: pop();
649: return(i);
650: }
651:
652: bidx(ip)
653: struct item *ip;
654: {
655: register struct item *p;
656:
657: p = ip;
658: idx.type = p->type;
659: idx.rank = p->rank;
660: copy(IN, p->dim, idx.dim, idx.rank);
661: size();
662: }
663:
664: size()
665: {
666: register i, s;
667:
668: s = 1;
669: for(i=idx.rank-1; i>=0; i--) {
670: idx.del[i] = s;
671: s *= idx.dim[i];
672: }
673: idx.size = s;
674: return(s);
675: }
676:
677: colapse(k)
678: {
679: register i;
680:
681: if(k < 0 || k >= idx.rank)
682: error("collapse X");
683: idx.dimk = idx.dim[k];
684: idx.delk = idx.del[k];
685: for(i=k; i<idx.rank; i++) {
686: idx.del[i] = idx.del[i+1];
687: idx.dim[i] = idx.dim[i+1];
688: }
689: if (idx.dimk)
690: idx.size /= idx.dimk;
691: idx.rank--;
692: }
693:
694: forloop(co, arg)
695: int (*co)();
696: {
697: register i;
698:
699: if (idx.size == 0)
700: return; /* for null items */
701: if(idx.rank == 0) {
702: (*co)(arg);
703: return;
704: }
705: for(i=0;;) {
706: while(i < idx.rank)
707: idx.idx[i++] = 0;
708: (*co)(arg);
709: while(++idx.idx[i-1] >= idx.dim[i-1])
710: if(--i <= 0)
711: return;
712: }
713: }
714:
715: access()
716: {
717: register i, n;
718:
719: n = 0;
720: for(i=0; i<idx.rank; i++)
721: n += idx.idx[i] * idx.del[i];
722: return(n);
723: }
724:
725: data
726: getdat(ip)
727: struct item *ip;
728: {
729: register struct item *p;
730: register i;
731: data d;
732:
733: /* Get the data value stored at index p->index. If the
734: * index is out of range it will be wrapped around. If
735: * the data item is null, a zero or blank will be returned.
736: */
737:
738: p = ip;
739: i = p->index;
740: while(i >= p->size) {
741: if (p->size == 0) /* let the caller beware */
742: return((p->type == DA) ? zero : (data)' ');
743: /*
744: if (i == 0)
745: error("getdat B");
746: */
747: i -= p->size;
748: }
749: if(p->type == DA) {
750: d = p->datap[i];
751: } else
752: if(p->type == CH) {
753: d = ((struct chrstrct *)p->datap)->c[i];
754: } else
755: error("getdat B");
756: i++;
757: p->index = i;
758: return(d);
759: }
760:
761: putdat(ip, d)
762: data d;
763: struct item *ip;
764: {
765: register struct item *p;
766: register i;
767:
768: p = ip;
769: i = p->index;
770: if(i >= p->size)
771: error("putdat B");
772: if(p->type == DA) {
773: p->datap[i] = d;
774: } else
775: if(p->type == CH) {
776: ((struct chrstrct *)p->datap)->c[i] = d;
777: } else
778: error("putdat B");
779: i++;
780: p->index = i;
781: }
782:
783: /* aplmod has been moved to am.c */
784:
785: struct item *
786: s2vect(ap)
787: struct item *ap;
788: {
789: register struct item *p, *q;
790:
791: p = ap;
792: q = newdat(p->type, 1, 1);
793: q->datap = p->datap;
794: q->dim[0] = 1;
795: return(q);
796: }
797:
798: struct nlist *
799: nlook(name)
800: char *name;
801: {
802: register struct nlist *np;
803:
804: for(np = nlist; np->namep; np++)
805: if(equal(np->namep, name))
806: return(np);
807: return(0);
808: }
809:
810: checksp()
811: {
812: if(sp >= &stack[STKS])
813: error("stack overflow");
814: }
815: char *
816: concat(s1,s2)
817: char *s1, *s2;
818: {
819: register i,j;
820: char *p,*q;
821:
822: i = lsize(s1) - 1;
823: j = lsize(s2) - 1;
824: p = q = alloc(i+j);
825: p += copy(CH, s1, p, i);
826: copy(CH, s2, p, j);
827: return(q);
828: }
829:
830: char *
831: catcode(s1,s2)
832: char *s1, *s2;
833: {
834: register i,j;
835: char *p,*q;
836:
837: i = csize(s1) - 1;
838: j = csize(s2);
839: p = q = alloc(i+j);
840: p += copy(CH, s1, p, i);
841: copy(CH, s2, p, j);
842: return(q);
843: }
844:
845: /*
846: * csize -- return size (in bytes) of a compiled string
847: */
848: csize(s)
849: char *s;
850: {
851: register c,len;
852: register char *p;
853: int i;
854:
855: len = 1;
856: p = s;
857: while((c = *p++) != EOF){
858: len++;
859: c &= 0377;
860: switch(c){
861: default:
862: i = 0;
863: break;
864:
865: case QUOT:
866: i = *p++;
867: break;
868:
869: case CONST:
870: i = *p++;
871: i *= SDAT;
872: len++;
873: break;
874:
875: case NAME:
876: case FUN:
877: case ARG1:
878: case ARG2:
879: case AUTO:
880: case REST:
881: case RVAL:
882: i = 2;
883: break;
884: }
885: p += i;
886: len += i;
887: }
888: return(len);
889: }
890:
891: opn(file, rw)
892: char file[];
893: {
894: register fd, (*p)();
895: char f2[100];
896: extern OPENF(), CREATF();
897:
898: p = (rw > 2 ? CREATF : OPENF);
899: if((fd = (*p)(file,rw)) < 0){
900: for(fd=0; fd<13; fd++)
901: f2[fd] = LIBDIR[fd];
902: for(fd=0; file[fd]; fd++)
903: f2[fd+13] = file[fd];
904: f2[fd+13] = 0;
905: if((fd = (*p)(f2, rw)) >= 0){
906: printf("[using %s]\n", f2);
907: return(fd);
908: }
909: printf("can't open file %s\n", file);
910: error("");
911: }
912: return(fd);
913: }
914:
915: catchsigs()
916: {
917: extern panic();
918:
919: signal(SIGHUP, panic);
920: signal(SIGQUIT, panic);
921: signal(SIGILL, panic);
922: signal(SIGTRAP, panic);
923: signal(SIGEMT, panic);
924: /* signal(SIGFPE, fpe); /* (fppinit called by "main") */
925: signal(SIGBUS, panic);
926: signal(SIGSEGV, panic);
927: signal(SIGSYS, panic);
928: signal(SIGPIPE, panic);
929: signal(SIGTERM, panic);
930: }
931:
932: panic(signum)
933: unsigned signum;
934: {
935:
936: register fd;
937: static insane = 0; /* if != 0, die */
938: static char *abt_file = "aplws.abort";
939: static char *errtbl[] = {
940: "excessive eofs",
941: "hangup",
942: "interrupt",
943: "quit",
944: "illegal instruction",
945: "trace trap",
946: "i/o trap instruction",
947: "emt trap",
948: "floating exception",
949: "kill",
950: "bus error",
951: "segmentation violation",
952: "bad system call",
953: "write no pipe",
954: "alarm clock",
955: "software termination"
956: };
957:
958: /* Attempt to save workspace. A signal out of here always
959: * causes immediate death.
960: */
961:
962: mencflg = 0;
963: signal(signum, panic);
964: printf("\nfatal signal: %s\n",
965: errtbl[(signum < NSIG) ? signum : 0]);
966:
967: if (mkcore) abort();
968:
969: if (!insane++){
970: if ((fd=CREATF(abt_file, 0644)) >= 0){
971: printf("[attempting ws dump]\n");
972: wssave(fd);
973: printf(" workspace saved in %s\n", abt_file);
974: CLOSEF(fd);
975: } else
976: printf("workspace lost -- sorry\n");
977: } else
978: printf("recursive errors: unrecoverable\n");
979:
980: term(0);
981: }
982: #ifdef vax
983: abort(){
984: kill(getpid(), SIGIOT);
985: exit(1);
986: }
987: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.