|
|
1.1 root 1: /* Copyright (c) 1979 Regents of the University of California */
2:
3: static char sccsid[] = "@(#)pcproc.c 1.21 4/8/83";
4:
5: #include "whoami.h"
6: #ifdef PC
7: /*
8: * and to the end of the file
9: */
10: #include "0.h"
11: #include "tree.h"
12: #include "objfmt.h"
13: #include "opcode.h"
14: #include "pc.h"
15: #include "pcops.h"
16: #include "tmps.h"
17:
18: /*
19: * The constant EXPOSIZE specifies the number of digits in the exponent
20: * of real numbers.
21: *
22: * The constant REALSPC defines the amount of forced padding preceeding
23: * real numbers when they are printed. If REALSPC == 0, then no padding
24: * is added, REALSPC == 1 adds one extra blank irregardless of the width
25: * specified by the user.
26: *
27: * N.B. - Values greater than one require program mods.
28: */
29: #define EXPOSIZE 2
30: #define REALSPC 0
31:
32: /*
33: * The following array is used to determine which classes may be read
34: * from textfiles. It is indexed by the return value from classify.
35: */
36: #define rdops(x) rdxxxx[(x)-(TFIRST)]
37:
38: int rdxxxx[] = {
39: 0, /* -7 file types */
40: 0, /* -6 record types */
41: 0, /* -5 array types */
42: O_READE, /* -4 scalar types */
43: 0, /* -3 pointer types */
44: 0, /* -2 set types */
45: 0, /* -1 string types */
46: 0, /* 0 nil, no type */
47: O_READE, /* 1 boolean */
48: O_READC, /* 2 character */
49: O_READ4, /* 3 integer */
50: O_READ8 /* 4 real */
51: };
52:
53: /*
54: * Proc handles procedure calls.
55: * Non-builtin procedures are "buck-passed" to func (with a flag
56: * indicating that they are actually procedures.
57: * builtin procedures are handled here.
58: */
59: pcproc(r)
60: int *r;
61: {
62: register struct nl *p;
63: register int *alv, *al, op;
64: struct nl *filetype, *ap;
65: int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file;
66: char fmt, format[20], *strptr, *cmd;
67: int prec, field, strnglen, fmtlen, fmtstart, pu;
68: int *pua, *pui, *puz;
69: int i, j, k;
70: int itemwidth;
71: char *readname;
72: struct nl *tempnlp;
73: long readtype;
74: struct tmps soffset;
75:
76: #define CONPREC 4
77: #define VARPREC 8
78: #define CONWIDTH 1
79: #define VARWIDTH 2
80: #define SKIP 16
81:
82: /*
83: * Verify that the name is
84: * defined and is that of a
85: * procedure.
86: */
87: p = lookup(r[2]);
88: if (p == NIL) {
89: rvlist(r[3]);
90: return;
91: }
92: if (p->class != PROC && p->class != FPROC) {
93: error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
94: rvlist(r[3]);
95: return;
96: }
97: argv = r[3];
98:
99: /*
100: * Call handles user defined
101: * procedures and functions.
102: */
103: if (bn != 0) {
104: call(p, argv, PROC, bn);
105: return;
106: }
107:
108: /*
109: * Call to built-in procedure.
110: * Count the arguments.
111: */
112: argc = 0;
113: for (al = argv; al != NIL; al = al[2])
114: argc++;
115:
116: /*
117: * Switch on the operator
118: * associated with the built-in
119: * procedure in the namelist
120: */
121: op = p->value[0] &~ NSTAND;
122: if (opt('s') && (p->value[0] & NSTAND)) {
123: standard();
124: error("%s is a nonstandard procedure", p->symbol);
125: }
126: switch (op) {
127:
128: case O_ABORT:
129: if (argc != 0)
130: error("null takes no arguments");
131: return;
132:
133: case O_FLUSH:
134: if (argc == 0) {
135: putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" );
136: putop( P2UNARY P2CALL , P2INT );
137: putdot( filename , line );
138: return;
139: }
140: if (argc != 1) {
141: error("flush takes at most one argument");
142: return;
143: }
144: putleaf( P2ICON , 0 , 0
145: , ADDTYPE( P2FTN | P2INT , P2PTR )
146: , "_FLUSH" );
147: ap = stklval(argv[1], NOFLAGS);
148: if (ap == NIL)
149: return;
150: if (ap->class != FILET) {
151: error("flush's argument must be a file, not %s", nameof(ap));
152: return;
153: }
154: putop( P2CALL , P2INT );
155: putdot( filename , line );
156: return;
157:
158: case O_MESSAGE:
159: case O_WRITEF:
160: case O_WRITLN:
161: /*
162: * Set up default file "output"'s type
163: */
164: file = NIL;
165: filetype = nl+T1CHAR;
166: /*
167: * Determine the file implied
168: * for the write and generate
169: * code to make it the active file.
170: */
171: if (op == O_MESSAGE) {
172: /*
173: * For message, all that matters
174: * is that the filetype is
175: * a character file.
176: * Thus "output" will suit us fine.
177: */
178: putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" );
179: putop( P2UNARY P2CALL , P2INT );
180: putdot( filename , line );
181: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
182: P2PTR|P2STRTY );
183: putLV( "__err" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY );
184: putop( P2ASSIGN , P2PTR|P2STRTY );
185: putdot( filename , line );
186: } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) {
187: /*
188: * If there is a first argument which has
189: * no write widths, then it is potentially
190: * a file name.
191: */
192: codeoff();
193: ap = stkrval(argv[1], NIL , RREQ );
194: codeon();
195: if (ap == NIL)
196: argv = argv[2];
197: if (ap != NIL && ap->class == FILET) {
198: /*
199: * Got "write(f, ...", make
200: * f the active file, and save
201: * it and its type for use in
202: * processing the rest of the
203: * arguments to write.
204: */
205: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
206: P2PTR|P2STRTY );
207: putleaf( P2ICON , 0 , 0
208: , ADDTYPE( P2FTN | P2INT , P2PTR )
209: , "_UNIT" );
210: file = argv[1];
211: filetype = ap->type;
212: stklval(argv[1], NOFLAGS);
213: putop( P2CALL , P2INT );
214: putop( P2ASSIGN , P2PTR|P2STRTY );
215: putdot( filename , line );
216: /*
217: * Skip over the first argument
218: */
219: argv = argv[2];
220: argc--;
221: } else {
222: /*
223: * Set up for writing on
224: * standard output.
225: */
226: putRV( 0, cbn , CURFILEOFFSET ,
227: NLOCAL , P2PTR|P2STRTY );
228: putLV( "_output" , 0 , 0 , NGLOBAL ,
229: P2PTR|P2STRTY );
230: putop( P2ASSIGN , P2PTR|P2STRTY );
231: putdot( filename , line );
232: output->nl_flags |= NUSED;
233: }
234: } else {
235: putRV( 0, cbn , CURFILEOFFSET , NLOCAL ,
236: P2PTR|P2STRTY );
237: putLV( "_output" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY );
238: putop( P2ASSIGN , P2PTR|P2STRTY );
239: putdot( filename , line );
240: output->nl_flags |= NUSED;
241: }
242: /*
243: * Loop and process each
244: * of the arguments.
245: */
246: for (; argv != NIL; argv = argv[2]) {
247: /*
248: * fmtspec indicates the type (CONstant or VARiable)
249: * and number (none, WIDTH, and/or PRECision)
250: * of the fields in the printf format for this
251: * output variable.
252: * stkcnt is the number of longs pushed on the stack
253: * fmt is the format output indicator (D, E, F, O, X, S)
254: * fmtstart = 0 for leading blank; = 1 for no blank
255: */
256: fmtspec = NIL;
257: stkcnt = 0;
258: fmt = 'D';
259: fmtstart = 1;
260: al = argv[1];
261: if (al == NIL)
262: continue;
263: if (al[0] == T_WEXP)
264: alv = al[1];
265: else
266: alv = al;
267: if (alv == NIL)
268: continue;
269: codeoff();
270: ap = stkrval(alv, NIL , RREQ );
271: codeon();
272: if (ap == NIL)
273: continue;
274: typ = classify(ap);
275: if (al[0] == T_WEXP) {
276: /*
277: * Handle width expressions.
278: * The basic game here is that width
279: * expressions get evaluated. If they
280: * are constant, the value is placed
281: * directly in the format string.
282: * Otherwise the value is pushed onto
283: * the stack and an indirection is
284: * put into the format string.
285: */
286: if (al[3] == OCT)
287: fmt = 'O';
288: else if (al[3] == HEX)
289: fmt = 'X';
290: else if (al[3] != NIL) {
291: /*
292: * Evaluate second format spec
293: */
294: if ( constval(al[3])
295: && isa( con.ctype , "i" ) ) {
296: fmtspec += CONPREC;
297: prec = con.crval;
298: } else {
299: fmtspec += VARPREC;
300: }
301: fmt = 'f';
302: switch ( typ ) {
303: case TINT:
304: if ( opt( 's' ) ) {
305: standard();
306: error("Writing %ss with two write widths is non-standard", clnames[typ]);
307: }
308: /* and fall through */
309: case TDOUBLE:
310: break;
311: default:
312: error("Cannot write %ss with two write widths", clnames[typ]);
313: continue;
314: }
315: }
316: /*
317: * Evaluate first format spec
318: */
319: if (al[2] != NIL) {
320: if ( constval(al[2])
321: && isa( con.ctype , "i" ) ) {
322: fmtspec += CONWIDTH;
323: field = con.crval;
324: } else {
325: fmtspec += VARWIDTH;
326: }
327: }
328: if ((fmtspec & CONPREC) && prec < 0 ||
329: (fmtspec & CONWIDTH) && field < 0) {
330: error("Negative widths are not allowed");
331: continue;
332: }
333: if ( opt('s') &&
334: ((fmtspec & CONPREC) && prec == 0 ||
335: (fmtspec & CONWIDTH) && field == 0)) {
336: standard();
337: error("Zero widths are non-standard");
338: }
339: }
340: if (filetype != nl+T1CHAR) {
341: if (fmt == 'O' || fmt == 'X') {
342: error("Oct/hex allowed only on text files");
343: continue;
344: }
345: if (fmtspec) {
346: error("Write widths allowed only on text files");
347: continue;
348: }
349: /*
350: * Generalized write, i.e.
351: * to a non-textfile.
352: */
353: putleaf( P2ICON , 0 , 0
354: , ADDTYPE(
355: ADDTYPE(
356: ADDTYPE( p2type( filetype )
357: , P2PTR )
358: , P2FTN )
359: , P2PTR )
360: , "_FNIL" );
361: stklval(file, NOFLAGS);
362: putop( P2CALL
363: , ADDTYPE( p2type( filetype ) , P2PTR ) );
364: putop( P2UNARY P2MUL , p2type( filetype ) );
365: /*
366: * file^ := ...
367: */
368: switch ( classify( filetype ) ) {
369: case TBOOL:
370: case TCHAR:
371: case TINT:
372: case TSCAL:
373: precheck( filetype , "_RANG4" , "_RSNG4" );
374: /* and fall through */
375: case TDOUBLE:
376: case TPTR:
377: ap = rvalue( argv[1] , filetype , RREQ );
378: break;
379: default:
380: ap = rvalue( argv[1] , filetype , LREQ );
381: break;
382: }
383: if (ap == NIL)
384: continue;
385: if (incompat(ap, filetype, argv[1])) {
386: cerror("Type mismatch in write to non-text file");
387: continue;
388: }
389: switch ( classify( filetype ) ) {
390: case TBOOL:
391: case TCHAR:
392: case TINT:
393: case TSCAL:
394: postcheck(filetype, ap);
395: sconv(p2type(ap), p2type(filetype));
396: /* and fall through */
397: case TDOUBLE:
398: case TPTR:
399: putop( P2ASSIGN , p2type( filetype ) );
400: putdot( filename , line );
401: break;
402: default:
403: putstrop(P2STASG,
404: ADDTYPE(p2type(filetype),
405: P2PTR),
406: lwidth(filetype),
407: align(filetype));
408: putdot( filename , line );
409: break;
410: }
411: /*
412: * put(file)
413: */
414: putleaf( P2ICON , 0 , 0
415: , ADDTYPE( P2FTN | P2INT , P2PTR )
416: , "_PUT" );
417: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
418: P2PTR|P2STRTY );
419: putop( P2CALL , P2INT );
420: putdot( filename , line );
421: continue;
422: }
423: /*
424: * Write to a textfile
425: *
426: * Evaluate the expression
427: * to be written.
428: */
429: if (fmt == 'O' || fmt == 'X') {
430: if (opt('s')) {
431: standard();
432: error("Oct and hex are non-standard");
433: }
434: if (typ == TSTR || typ == TDOUBLE) {
435: error("Can't write %ss with oct/hex", clnames[typ]);
436: continue;
437: }
438: if (typ == TCHAR || typ == TBOOL)
439: typ = TINT;
440: }
441: /*
442: * If there is no format specified by the programmer,
443: * implement the default.
444: */
445: switch (typ) {
446: case TPTR:
447: warning();
448: if (opt('s')) {
449: standard();
450: }
451: error("Writing %ss to text files is non-standard",
452: clnames[typ]);
453: /* and fall through */
454: case TINT:
455: if (fmt == 'f') {
456: typ = TDOUBLE;
457: goto tdouble;
458: }
459: if (fmtspec == NIL) {
460: if (fmt == 'D')
461: field = 10;
462: else if (fmt == 'X')
463: field = 8;
464: else if (fmt == 'O')
465: field = 11;
466: else
467: panic("fmt1");
468: fmtspec = CONWIDTH;
469: }
470: break;
471: case TCHAR:
472: tchar:
473: fmt = 'c';
474: break;
475: case TSCAL:
476: warning();
477: if (opt('s')) {
478: standard();
479: }
480: error("Writing %ss to text files is non-standard",
481: clnames[typ]);
482: case TBOOL:
483: fmt = 's';
484: break;
485: case TDOUBLE:
486: tdouble:
487: switch (fmtspec) {
488: case NIL:
489: field = 14 + (5 + EXPOSIZE);
490: prec = field - (5 + EXPOSIZE);
491: fmt = 'e';
492: fmtspec = CONWIDTH + CONPREC;
493: break;
494: case CONWIDTH:
495: field -= REALSPC;
496: if (field < 1)
497: field = 1;
498: prec = field - (5 + EXPOSIZE);
499: if (prec < 1)
500: prec = 1;
501: fmtspec += CONPREC;
502: fmt = 'e';
503: break;
504: case VARWIDTH:
505: fmtspec += VARPREC;
506: fmt = 'e';
507: break;
508: case CONWIDTH + CONPREC:
509: case CONWIDTH + VARPREC:
510: field -= REALSPC;
511: if (field < 1)
512: field = 1;
513: }
514: format[0] = ' ';
515: fmtstart = 1 - REALSPC;
516: break;
517: case TSTR:
518: constval( alv );
519: switch ( classify( con.ctype ) ) {
520: case TCHAR:
521: typ = TCHAR;
522: goto tchar;
523: case TSTR:
524: strptr = con.cpval;
525: for (strnglen = 0; *strptr++; strnglen++) /* void */;
526: strptr = con.cpval;
527: break;
528: default:
529: strnglen = width(ap);
530: break;
531: }
532: fmt = 's';
533: strfmt = fmtspec;
534: if (fmtspec == NIL) {
535: fmtspec = SKIP;
536: break;
537: }
538: if (fmtspec & CONWIDTH) {
539: if (field <= strnglen)
540: fmtspec = SKIP;
541: else
542: field -= strnglen;
543: }
544: break;
545: default:
546: error("Can't write %ss to a text file", clnames[typ]);
547: continue;
548: }
549: /*
550: * Generate the format string
551: */
552: switch (fmtspec) {
553: default:
554: panic("fmt2");
555: case NIL:
556: if (fmt == 'c') {
557: if ( opt( 't' ) ) {
558: putleaf( P2ICON , 0 , 0
559: , ADDTYPE( P2FTN|P2INT , P2PTR )
560: , "_WRITEC" );
561: putRV( 0 , cbn , CURFILEOFFSET ,
562: NLOCAL , P2PTR|P2STRTY );
563: stkrval( alv , NIL , RREQ );
564: putop( P2LISTOP , P2INT );
565: } else {
566: putleaf( P2ICON , 0 , 0
567: , ADDTYPE( P2FTN|P2INT , P2PTR )
568: , "_fputc" );
569: stkrval( alv , NIL , RREQ );
570: }
571: putleaf( P2ICON , 0 , 0
572: , ADDTYPE( P2FTN | P2INT , P2PTR )
573: , "_ACTFILE" );
574: putRV( 0, cbn , CURFILEOFFSET ,
575: NLOCAL , P2PTR|P2STRTY );
576: putop( P2CALL , P2INT );
577: putop( P2LISTOP , P2INT );
578: putop( P2CALL , P2INT );
579: putdot( filename , line );
580: } else {
581: sprintf(&format[1], "%%%c", fmt);
582: goto fmtgen;
583: }
584: case SKIP:
585: break;
586: case CONWIDTH:
587: sprintf(&format[1], "%%%1D%c", field, fmt);
588: goto fmtgen;
589: case VARWIDTH:
590: sprintf(&format[1], "%%*%c", fmt);
591: goto fmtgen;
592: case CONWIDTH + CONPREC:
593: sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt);
594: goto fmtgen;
595: case CONWIDTH + VARPREC:
596: sprintf(&format[1], "%%%1D.*%c", field, fmt);
597: goto fmtgen;
598: case VARWIDTH + CONPREC:
599: sprintf(&format[1], "%%*.%1D%c", prec, fmt);
600: goto fmtgen;
601: case VARWIDTH + VARPREC:
602: sprintf(&format[1], "%%*.*%c", fmt);
603: fmtgen:
604: if ( opt( 't' ) ) {
605: putleaf( P2ICON , 0 , 0
606: , ADDTYPE( P2FTN | P2INT , P2PTR )
607: , "_WRITEF" );
608: putRV( 0 , cbn , CURFILEOFFSET ,
609: NLOCAL , P2PTR|P2STRTY );
610: putleaf( P2ICON , 0 , 0
611: , ADDTYPE( P2FTN | P2INT , P2PTR )
612: , "_ACTFILE" );
613: putRV( 0 , cbn , CURFILEOFFSET ,
614: NLOCAL , P2PTR|P2STRTY );
615: putop( P2CALL , P2INT );
616: putop( P2LISTOP , P2INT );
617: } else {
618: putleaf( P2ICON , 0 , 0
619: , ADDTYPE( P2FTN | P2INT , P2PTR )
620: , "_fprintf" );
621: putleaf( P2ICON , 0 , 0
622: , ADDTYPE( P2FTN | P2INT , P2PTR )
623: , "_ACTFILE" );
624: putRV( 0 , cbn , CURFILEOFFSET ,
625: NLOCAL , P2PTR|P2STRTY );
626: putop( P2CALL , P2INT );
627: }
628: putCONG( &format[ fmtstart ]
629: , strlen( &format[ fmtstart ] )
630: , LREQ );
631: putop( P2LISTOP , P2INT );
632: if ( fmtspec & VARWIDTH ) {
633: /*
634: * either
635: * ,(temp=width,MAX(temp,...)),
636: * or
637: * , MAX( width , ... ) ,
638: */
639: if ( ( typ == TDOUBLE && al[3] == NIL )
640: || typ == TSTR ) {
641: soffset = sizes[cbn].curtmps;
642: tempnlp = tmpalloc(sizeof(long),
643: nl+T4INT, REGOK);
644: putRV( 0 , cbn ,
645: tempnlp -> value[ NL_OFFS ] ,
646: tempnlp -> extra_flags , P2INT );
647: ap = stkrval( al[2] , NIL , RREQ );
648: putop( P2ASSIGN , P2INT );
649: putleaf( P2ICON , 0 , 0
650: , ADDTYPE( P2FTN | P2INT , P2PTR )
651: , "_MAX" );
652: putRV( 0 , cbn ,
653: tempnlp -> value[ NL_OFFS ] ,
654: tempnlp -> extra_flags , P2INT );
655: } else {
656: if (opt('t')
657: || typ == TSTR || typ == TDOUBLE) {
658: putleaf( P2ICON , 0 , 0
659: ,ADDTYPE( P2FTN | P2INT, P2PTR )
660: ,"_MAX" );
661: }
662: ap = stkrval( al[2] , NIL , RREQ );
663: }
664: if (ap == NIL)
665: continue;
666: if (isnta(ap,"i")) {
667: error("First write width must be integer, not %s", nameof(ap));
668: continue;
669: }
670: switch ( typ ) {
671: case TDOUBLE:
672: putleaf( P2ICON , REALSPC , 0 , P2INT , 0 );
673: putop( P2LISTOP , P2INT );
674: putleaf( P2ICON , 1 , 0 , P2INT , 0 );
675: putop( P2LISTOP , P2INT );
676: putop( P2CALL , P2INT );
677: if ( al[3] == NIL ) {
678: /*
679: * finish up the comma op
680: */
681: putop( P2COMOP , P2INT );
682: fmtspec &= ~VARPREC;
683: putop( P2LISTOP , P2INT );
684: putleaf( P2ICON , 0 , 0
685: , ADDTYPE( P2FTN | P2INT , P2PTR )
686: , "_MAX" );
687: putRV( 0 , cbn ,
688: tempnlp -> value[ NL_OFFS ] ,
689: tempnlp -> extra_flags ,
690: P2INT );
691: tmpfree(&soffset);
692: putleaf( P2ICON ,
693: 5 + EXPOSIZE + REALSPC ,
694: 0 , P2INT , 0 );
695: putop( P2LISTOP , P2INT );
696: putleaf( P2ICON , 1 , 0 , P2INT , 0 );
697: putop( P2LISTOP , P2INT );
698: putop( P2CALL , P2INT );
699: }
700: putop( P2LISTOP , P2INT );
701: break;
702: case TSTR:
703: putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
704: putop( P2LISTOP , P2INT );
705: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
706: putop( P2LISTOP , P2INT );
707: putop( P2CALL , P2INT );
708: putop( P2COMOP , P2INT );
709: putop( P2LISTOP , P2INT );
710: break;
711: default:
712: if (opt('t')) {
713: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
714: putop( P2LISTOP , P2INT );
715: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
716: putop( P2LISTOP , P2INT );
717: putop( P2CALL , P2INT );
718: }
719: putop( P2LISTOP , P2INT );
720: break;
721: }
722: }
723: /*
724: * If there is a variable precision,
725: * evaluate it
726: */
727: if (fmtspec & VARPREC) {
728: if (opt('t')) {
729: putleaf( P2ICON , 0 , 0
730: , ADDTYPE( P2FTN | P2INT , P2PTR )
731: , "_MAX" );
732: }
733: ap = stkrval( al[3] , NIL , RREQ );
734: if (ap == NIL)
735: continue;
736: if (isnta(ap,"i")) {
737: error("Second write width must be integer, not %s", nameof(ap));
738: continue;
739: }
740: if (opt('t')) {
741: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
742: putop( P2LISTOP , P2INT );
743: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
744: putop( P2LISTOP , P2INT );
745: putop( P2CALL , P2INT );
746: }
747: putop( P2LISTOP , P2INT );
748: }
749: /*
750: * evaluate the thing we want printed.
751: */
752: switch ( typ ) {
753: case TPTR:
754: case TCHAR:
755: case TINT:
756: stkrval( alv , NIL , RREQ );
757: putop( P2LISTOP , P2INT );
758: break;
759: case TDOUBLE:
760: ap = stkrval( alv , NIL , RREQ );
761: if (isnta(ap, "d")) {
762: sconv(p2type(ap), P2DOUBLE);
763: }
764: putop( P2LISTOP , P2INT );
765: break;
766: case TSCAL:
767: case TBOOL:
768: putleaf( P2ICON , 0 , 0
769: , ADDTYPE( P2FTN | P2INT , P2PTR )
770: , "_NAM" );
771: ap = stkrval( alv , NIL , RREQ );
772: sprintf( format , PREFIXFORMAT , LABELPREFIX
773: , listnames( ap ) );
774: putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR
775: , format );
776: putop( P2LISTOP , P2INT );
777: putop( P2CALL , P2INT );
778: putop( P2LISTOP , P2INT );
779: break;
780: case TSTR:
781: putCONG( "" , 0 , LREQ );
782: putop( P2LISTOP , P2INT );
783: break;
784: default:
785: panic("fmt3");
786: break;
787: }
788: putop( P2CALL , P2INT );
789: putdot( filename , line );
790: }
791: /*
792: * Write the string after its blank padding
793: */
794: if (typ == TSTR ) {
795: if ( opt( 't' ) ) {
796: putleaf( P2ICON , 0 , 0
797: , ADDTYPE( P2FTN | P2INT , P2PTR )
798: , "_WRITES" );
799: putRV( 0 , cbn , CURFILEOFFSET ,
800: NLOCAL , P2PTR|P2STRTY );
801: ap = stkrval(alv, NIL , RREQ );
802: putop( P2LISTOP , P2INT );
803: } else {
804: putleaf( P2ICON , 0 , 0
805: , ADDTYPE( P2FTN | P2INT , P2PTR )
806: , "_fwrite" );
807: ap = stkrval(alv, NIL , RREQ );
808: }
809: if (strfmt & VARWIDTH) {
810: /*
811: * min, inline expanded as
812: * temp < len ? temp : len
813: */
814: putRV( 0 , cbn ,
815: tempnlp -> value[ NL_OFFS ] ,
816: tempnlp -> extra_flags , P2INT );
817: putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
818: putop( P2LT , P2INT );
819: putRV( 0 , cbn ,
820: tempnlp -> value[ NL_OFFS ] ,
821: tempnlp -> extra_flags , P2INT );
822: putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
823: putop( P2COLON , P2INT );
824: putop( P2QUEST , P2INT );
825: tmpfree(&soffset);
826: } else {
827: if ( ( fmtspec & SKIP )
828: && ( strfmt & CONWIDTH ) ) {
829: strnglen = field;
830: }
831: putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
832: }
833: putop( P2LISTOP , P2INT );
834: putleaf( P2ICON , 1 , 0 , P2INT , 0 );
835: putop( P2LISTOP , P2INT );
836: putleaf( P2ICON , 0 , 0
837: , ADDTYPE( P2FTN | P2INT , P2PTR )
838: , "_ACTFILE" );
839: putRV( 0, cbn , CURFILEOFFSET , NLOCAL ,
840: P2PTR|P2STRTY );
841: putop( P2CALL , P2INT );
842: putop( P2LISTOP , P2INT );
843: putop( P2CALL , P2INT );
844: putdot( filename , line );
845: }
846: }
847: /*
848: * Done with arguments.
849: * Handle writeln and
850: * insufficent number of args.
851: */
852: switch (p->value[0] &~ NSTAND) {
853: case O_WRITEF:
854: if (argc == 0)
855: error("Write requires an argument");
856: break;
857: case O_MESSAGE:
858: if (argc == 0)
859: error("Message requires an argument");
860: case O_WRITLN:
861: if (filetype != nl+T1CHAR)
862: error("Can't 'writeln' a non text file");
863: if ( opt( 't' ) ) {
864: putleaf( P2ICON , 0 , 0
865: , ADDTYPE( P2FTN | P2INT , P2PTR )
866: , "_WRITLN" );
867: putRV( 0 , cbn , CURFILEOFFSET ,
868: NLOCAL , P2PTR|P2STRTY );
869: } else {
870: putleaf( P2ICON , 0 , 0
871: , ADDTYPE( P2FTN | P2INT , P2PTR )
872: , "_fputc" );
873: putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 );
874: putleaf( P2ICON , 0 , 0
875: , ADDTYPE( P2FTN | P2INT , P2PTR )
876: , "_ACTFILE" );
877: putRV( 0 , cbn , CURFILEOFFSET ,
878: NLOCAL , P2PTR|P2STRTY );
879: putop( P2CALL , P2INT );
880: putop( P2LISTOP , P2INT );
881: }
882: putop( P2CALL , P2INT );
883: putdot( filename , line );
884: break;
885: }
886: return;
887:
888: case O_READ4:
889: case O_READLN:
890: /*
891: * Set up default
892: * file "input".
893: */
894: file = NIL;
895: filetype = nl+T1CHAR;
896: /*
897: * Determine the file implied
898: * for the read and generate
899: * code to make it the active file.
900: */
901: if (argv != NIL) {
902: codeoff();
903: ap = stkrval(argv[1], NIL , RREQ );
904: codeon();
905: if (ap == NIL)
906: argv = argv[2];
907: if (ap != NIL && ap->class == FILET) {
908: /*
909: * Got "read(f, ...", make
910: * f the active file, and save
911: * it and its type for use in
912: * processing the rest of the
913: * arguments to read.
914: */
915: file = argv[1];
916: filetype = ap->type;
917: putRV( 0, cbn , CURFILEOFFSET , NLOCAL ,
918: P2PTR|P2STRTY );
919: putleaf( P2ICON , 0 , 0
920: , ADDTYPE( P2FTN | P2INT , P2PTR )
921: , "_UNIT" );
922: stklval(argv[1], NOFLAGS);
923: putop( P2CALL , P2INT );
924: putop( P2ASSIGN , P2PTR|P2STRTY );
925: putdot( filename , line );
926: argv = argv[2];
927: argc--;
928: } else {
929: /*
930: * Default is read from
931: * standard input.
932: */
933: putRV( 0, cbn , CURFILEOFFSET , NLOCAL ,
934: P2PTR|P2STRTY );
935: putLV( "_input" , 0 , 0 , NGLOBAL ,
936: P2PTR|P2STRTY );
937: putop( P2ASSIGN , P2PTR|P2STRTY );
938: putdot( filename , line );
939: input->nl_flags |= NUSED;
940: }
941: } else {
942: putRV( 0, cbn , CURFILEOFFSET , NLOCAL ,
943: P2PTR|P2STRTY );
944: putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY );
945: putop( P2ASSIGN , P2PTR|P2STRTY );
946: putdot( filename , line );
947: input->nl_flags |= NUSED;
948: }
949: /*
950: * Loop and process each
951: * of the arguments.
952: */
953: for (; argv != NIL; argv = argv[2]) {
954: /*
955: * Get the address of the target
956: * on the stack.
957: */
958: al = argv[1];
959: if (al == NIL)
960: continue;
961: if (al[0] != T_VAR) {
962: error("Arguments to %s must be variables, not expressions", p->symbol);
963: continue;
964: }
965: codeoff();
966: ap = stklval(al, MOD|ASGN|NOUSE);
967: codeon();
968: if (ap == NIL)
969: continue;
970: if (filetype != nl+T1CHAR) {
971: /*
972: * Generalized read, i.e.
973: * from a non-textfile.
974: */
975: if (incompat(filetype, ap, argv[1] )) {
976: error("Type mismatch in read from non-text file");
977: continue;
978: }
979: /*
980: * var := file ^;
981: */
982: ap = lvalue( al , MOD | ASGN | NOUSE , RREQ );
983: if ( isa( ap , "bsci" ) ) {
984: precheck( ap , "_RANG4" , "_RSNG4" );
985: }
986: putleaf( P2ICON , 0 , 0
987: , ADDTYPE(
988: ADDTYPE(
989: ADDTYPE(
990: p2type( filetype ) , P2PTR )
991: , P2FTN )
992: , P2PTR )
993: , "_FNIL" );
994: if (file != NIL)
995: stklval(file, NOFLAGS);
996: else /* Magic */
997: putRV( "_input" , 0 , 0 , NGLOBAL ,
998: P2PTR | P2STRTY );
999: putop(P2CALL, ADDTYPE(p2type(filetype), P2PTR));
1000: switch ( classify( filetype ) ) {
1001: case TBOOL:
1002: case TCHAR:
1003: case TINT:
1004: case TSCAL:
1005: case TDOUBLE:
1006: case TPTR:
1007: putop( P2UNARY P2MUL
1008: , p2type( filetype ) );
1009: }
1010: switch ( classify( filetype ) ) {
1011: case TBOOL:
1012: case TCHAR:
1013: case TINT:
1014: case TSCAL:
1015: postcheck(ap, filetype);
1016: sconv(p2type(filetype), p2type(ap));
1017: /* and fall through */
1018: case TDOUBLE:
1019: case TPTR:
1020: putop( P2ASSIGN , p2type( ap ) );
1021: putdot( filename , line );
1022: break;
1023: default:
1024: putstrop(P2STASG,
1025: ADDTYPE(p2type(ap), P2PTR),
1026: lwidth(ap),
1027: align(ap));
1028: putdot( filename , line );
1029: break;
1030: }
1031: /*
1032: * get(file);
1033: */
1034: putleaf( P2ICON , 0 , 0
1035: , ADDTYPE( P2FTN | P2INT , P2PTR )
1036: , "_GET" );
1037: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
1038: P2PTR|P2STRTY );
1039: putop( P2CALL , P2INT );
1040: putdot( filename , line );
1041: continue;
1042: }
1043: /*
1044: * if you get to here, you are reading from
1045: * a text file. only possiblities are:
1046: * character, integer, real, or scalar.
1047: * read( f , foo , ... ) is done as
1048: * foo := read( f ) with rangechecking
1049: * if appropriate.
1050: */
1051: typ = classify(ap);
1052: op = rdops(typ);
1053: if (op == NIL) {
1054: error("Can't read %ss from a text file", clnames[typ]);
1055: continue;
1056: }
1057: /*
1058: * left hand side of foo := read( f )
1059: */
1060: ap = lvalue( al , MOD|ASGN|NOUSE , RREQ );
1061: if ( isa( ap , "bsci" ) ) {
1062: precheck( ap , "_RANG4" , "_RSNG4" );
1063: }
1064: switch ( op ) {
1065: case O_READC:
1066: readname = "_READC";
1067: readtype = P2INT;
1068: break;
1069: case O_READ4:
1070: readname = "_READ4";
1071: readtype = P2INT;
1072: break;
1073: case O_READ8:
1074: readname = "_READ8";
1075: readtype = P2DOUBLE;
1076: break;
1077: case O_READE:
1078: readname = "_READE";
1079: readtype = P2INT;
1080: break;
1081: }
1082: putleaf( P2ICON , 0 , 0
1083: , ADDTYPE( P2FTN | readtype , P2PTR )
1084: , readname );
1085: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
1086: P2PTR|P2STRTY );
1087: if ( op == O_READE ) {
1088: sprintf( format , PREFIXFORMAT , LABELPREFIX
1089: , listnames( ap ) );
1090: putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR
1091: , format );
1092: putop( P2LISTOP , P2INT );
1093: warning();
1094: if (opt('s')) {
1095: standard();
1096: }
1097: error("Reading scalars from text files is non-standard");
1098: }
1099: putop( P2CALL , readtype );
1100: if ( isa( ap , "bcsi" ) ) {
1101: postcheck(ap, readtype==P2INT?nl+T4INT:nl+TDOUBLE);
1102: }
1103: sconv(readtype, p2type(ap));
1104: putop( P2ASSIGN , p2type( ap ) );
1105: putdot( filename , line );
1106: }
1107: /*
1108: * Done with arguments.
1109: * Handle readln and
1110: * insufficient number of args.
1111: */
1112: if (p->value[0] == O_READLN) {
1113: if (filetype != nl+T1CHAR)
1114: error("Can't 'readln' a non text file");
1115: putleaf( P2ICON , 0 , 0
1116: , ADDTYPE( P2FTN | P2INT , P2PTR )
1117: , "_READLN" );
1118: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL ,
1119: P2PTR|P2STRTY );
1120: putop( P2CALL , P2INT );
1121: putdot( filename , line );
1122: } else if (argc == 0)
1123: error("read requires an argument");
1124: return;
1125:
1126: case O_GET:
1127: case O_PUT:
1128: if (argc != 1) {
1129: error("%s expects one argument", p->symbol);
1130: return;
1131: }
1132: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1133: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1134: , "_UNIT" );
1135: ap = stklval(argv[1], NOFLAGS);
1136: if (ap == NIL)
1137: return;
1138: if (ap->class != FILET) {
1139: error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
1140: return;
1141: }
1142: putop( P2CALL , P2INT );
1143: putop( P2ASSIGN , P2PTR|P2STRTY );
1144: putdot( filename , line );
1145: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1146: , op == O_GET ? "_GET" : "_PUT" );
1147: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1148: putop( P2CALL , P2INT );
1149: putdot( filename , line );
1150: return;
1151:
1152: case O_RESET:
1153: case O_REWRITE:
1154: if (argc == 0 || argc > 2) {
1155: error("%s expects one or two arguments", p->symbol);
1156: return;
1157: }
1158: if (opt('s') && argc == 2) {
1159: standard();
1160: error("Two argument forms of reset and rewrite are non-standard");
1161: }
1162: putleaf( P2ICON , 0 , 0 , P2INT
1163: , op == O_RESET ? "_RESET" : "_REWRITE" );
1164: ap = stklval(argv[1], MOD|NOUSE);
1165: if (ap == NIL)
1166: return;
1167: if (ap->class != FILET) {
1168: error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
1169: return;
1170: }
1171: if (argc == 2) {
1172: /*
1173: * Optional second argument
1174: * is a string name of a
1175: * UNIX (R) file to be associated.
1176: */
1177: al = argv[2];
1178: al = stkrval(al[1], NOFLAGS , RREQ );
1179: if (al == NIL)
1180: return;
1181: if (classify(al) != TSTR) {
1182: error("Second argument to %s must be a string, not %s", p->symbol, nameof(al));
1183: return;
1184: }
1185: strnglen = width(al);
1186: } else {
1187: putleaf( P2ICON , 0 , 0 , P2INT , 0 );
1188: strnglen = 0;
1189: }
1190: putop( P2LISTOP , P2INT );
1191: putleaf( P2ICON , strnglen , 0 , P2INT , 0 );
1192: putop( P2LISTOP , P2INT );
1193: putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 );
1194: putop( P2LISTOP , P2INT );
1195: putop( P2CALL , P2INT );
1196: putdot( filename , line );
1197: return;
1198:
1199: case O_NEW:
1200: case O_DISPOSE:
1201: if (argc == 0) {
1202: error("%s expects at least one argument", p->symbol);
1203: return;
1204: }
1205: alv = argv[1];
1206: codeoff();
1207: ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD );
1208: codeon();
1209: if (ap == NIL)
1210: return;
1211: if (ap->class != PTR) {
1212: error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
1213: return;
1214: }
1215: ap = ap->type;
1216: if (ap == NIL)
1217: return;
1218: if (op == O_NEW)
1219: cmd = "_NEW";
1220: else /* op == O_DISPOSE */
1221: if ((ap->nl_flags & NFILES) != 0)
1222: cmd = "_DFDISPOSE";
1223: else
1224: cmd = "_DISPOSE";
1225: putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd);
1226: stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD );
1227: argv = argv[2];
1228: if (argv != NIL) {
1229: if (ap->class != RECORD) {
1230: error("Record required when specifying variant tags");
1231: return;
1232: }
1233: for (; argv != NIL; argv = argv[2]) {
1234: if (ap->ptr[NL_VARNT] == NIL) {
1235: error("Too many tag fields");
1236: return;
1237: }
1238: if (!isconst(argv[1])) {
1239: error("Second and successive arguments to %s must be constants", p->symbol);
1240: return;
1241: }
1242: gconst(argv[1]);
1243: if (con.ctype == NIL)
1244: return;
1245: if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) {
1246: cerror("Specified tag constant type clashed with variant case selector type");
1247: return;
1248: }
1249: for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
1250: if (ap->range[0] == con.crval)
1251: break;
1252: if (ap == NIL) {
1253: error("No variant case label value equals specified constant value");
1254: return;
1255: }
1256: ap = ap->ptr[NL_VTOREC];
1257: }
1258: }
1259: putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1260: putop( P2LISTOP , P2INT );
1261: putop( P2CALL , P2INT );
1262: putdot( filename , line );
1263: if (opt('t') && op == O_NEW) {
1264: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1265: , "_blkclr" );
1266: stkrval(alv, NIL , RREQ );
1267: putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1268: putop( P2LISTOP , P2INT );
1269: putop( P2CALL , P2INT );
1270: putdot( filename , line );
1271: }
1272: return;
1273:
1274: case O_DATE:
1275: case O_TIME:
1276: if (argc != 1) {
1277: error("%s expects one argument", p->symbol);
1278: return;
1279: }
1280: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1281: , op == O_DATE ? "_DATE" : "_TIME" );
1282: ap = stklval(argv[1], MOD|NOUSE);
1283: if (ap == NIL)
1284: return;
1285: if (classify(ap) != TSTR || width(ap) != 10) {
1286: error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
1287: return;
1288: }
1289: putop( P2CALL , P2INT );
1290: putdot( filename , line );
1291: return;
1292:
1293: case O_HALT:
1294: if (argc != 0) {
1295: error("halt takes no arguments");
1296: return;
1297: }
1298: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1299: , "_HALT" );
1300:
1301: putop( P2UNARY P2CALL , P2INT );
1302: putdot( filename , line );
1303: noreach = 1;
1304: return;
1305:
1306: case O_ARGV:
1307: if (argc != 2) {
1308: error("argv takes two arguments");
1309: return;
1310: }
1311: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1312: , "_ARGV" );
1313: ap = stkrval(argv[1], NIL , RREQ );
1314: if (ap == NIL)
1315: return;
1316: if (isnta(ap, "i")) {
1317: error("argv's first argument must be an integer, not %s", nameof(ap));
1318: return;
1319: }
1320: al = argv[2];
1321: ap = stklval(al[1], MOD|NOUSE);
1322: if (ap == NIL)
1323: return;
1324: if (classify(ap) != TSTR) {
1325: error("argv's second argument must be a string, not %s", nameof(ap));
1326: return;
1327: }
1328: putop( P2LISTOP , P2INT );
1329: putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1330: putop( P2LISTOP , P2INT );
1331: putop( P2CALL , P2INT );
1332: putdot( filename , line );
1333: return;
1334:
1335: case O_STLIM:
1336: if (argc != 1) {
1337: error("stlimit requires one argument");
1338: return;
1339: }
1340: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1341: , "_STLIM" );
1342: ap = stkrval(argv[1], NIL , RREQ );
1343: if (ap == NIL)
1344: return;
1345: if (isnta(ap, "i")) {
1346: error("stlimit's argument must be an integer, not %s", nameof(ap));
1347: return;
1348: }
1349: putop( P2CALL , P2INT );
1350: putdot( filename , line );
1351: return;
1352:
1353: case O_REMOVE:
1354: if (argc != 1) {
1355: error("remove expects one argument");
1356: return;
1357: }
1358: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1359: , "_REMOVE" );
1360: ap = stkrval(argv[1], NOFLAGS , RREQ );
1361: if (ap == NIL)
1362: return;
1363: if (classify(ap) != TSTR) {
1364: error("remove's argument must be a string, not %s", nameof(ap));
1365: return;
1366: }
1367: putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 );
1368: putop( P2LISTOP , P2INT );
1369: putop( P2CALL , P2INT );
1370: putdot( filename , line );
1371: return;
1372:
1373: case O_LLIMIT:
1374: if (argc != 2) {
1375: error("linelimit expects two arguments");
1376: return;
1377: }
1378: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1379: , "_LLIMIT" );
1380: ap = stklval(argv[1], NOFLAGS|NOUSE);
1381: if (ap == NIL)
1382: return;
1383: if (!text(ap)) {
1384: error("linelimit's first argument must be a text file, not %s", nameof(ap));
1385: return;
1386: }
1387: al = argv[2];
1388: ap = stkrval(al[1], NIL , RREQ );
1389: if (ap == NIL)
1390: return;
1391: if (isnta(ap, "i")) {
1392: error("linelimit's second argument must be an integer, not %s", nameof(ap));
1393: return;
1394: }
1395: putop( P2LISTOP , P2INT );
1396: putop( P2CALL , P2INT );
1397: putdot( filename , line );
1398: return;
1399: case O_PAGE:
1400: if (argc != 1) {
1401: error("page expects one argument");
1402: return;
1403: }
1404: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1405: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1406: , "_UNIT" );
1407: ap = stklval(argv[1], NOFLAGS);
1408: if (ap == NIL)
1409: return;
1410: if (!text(ap)) {
1411: error("Argument to page must be a text file, not %s", nameof(ap));
1412: return;
1413: }
1414: putop( P2CALL , P2INT );
1415: putop( P2ASSIGN , P2PTR|P2STRTY );
1416: putdot( filename , line );
1417: if ( opt( 't' ) ) {
1418: putleaf( P2ICON , 0 , 0
1419: , ADDTYPE( P2FTN | P2INT , P2PTR )
1420: , "_PAGE" );
1421: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1422: } else {
1423: putleaf( P2ICON , 0 , 0
1424: , ADDTYPE( P2FTN | P2INT , P2PTR )
1425: , "_fputc" );
1426: putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 );
1427: putleaf( P2ICON , 0 , 0
1428: , ADDTYPE( P2FTN | P2INT , P2PTR )
1429: , "_ACTFILE" );
1430: putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY );
1431: putop( P2CALL , P2INT );
1432: putop( P2LISTOP , P2INT );
1433: }
1434: putop( P2CALL , P2INT );
1435: putdot( filename , line );
1436: return;
1437:
1438: case O_ASRT:
1439: if (!opt('t'))
1440: return;
1441: if (argc == 0 || argc > 2) {
1442: error("Assert expects one or two arguments");
1443: return;
1444: }
1445: if (argc == 2)
1446: cmd = "_ASRTS";
1447: else
1448: cmd = "_ASRT";
1449: putleaf( P2ICON , 0 , 0
1450: , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd );
1451: ap = stkrval(argv[1], NIL , RREQ );
1452: if (ap == NIL)
1453: return;
1454: if (isnta(ap, "b"))
1455: error("Assert expression must be Boolean, not %ss", nameof(ap));
1456: if (argc == 2) {
1457: /*
1458: * Optional second argument is a string specifying
1459: * why the assertion failed.
1460: */
1461: al = argv[2];
1462: al = stkrval(al[1], NIL , RREQ );
1463: if (al == NIL)
1464: return;
1465: if (classify(al) != TSTR) {
1466: error("Second argument to assert must be a string, not %s", nameof(al));
1467: return;
1468: }
1469: putop( P2LISTOP , P2INT );
1470: }
1471: putop( P2CALL , P2INT );
1472: putdot( filename , line );
1473: return;
1474:
1475: case O_PACK:
1476: if (argc != 3) {
1477: error("pack expects three arguments");
1478: return;
1479: }
1480: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1481: , "_PACK" );
1482: pu = "pack(a,i,z)";
1483: pua = (al = argv)[1];
1484: pui = (al = al[2])[1];
1485: puz = (al = al[2])[1];
1486: goto packunp;
1487: case O_UNPACK:
1488: if (argc != 3) {
1489: error("unpack expects three arguments");
1490: return;
1491: }
1492: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
1493: , "_UNPACK" );
1494: pu = "unpack(z,a,i)";
1495: puz = (al = argv)[1];
1496: pua = (al = al[2])[1];
1497: pui = (al = al[2])[1];
1498: packunp:
1499: ap = stkrval((int *) pui, NLNIL , RREQ );
1500: if (ap == NIL)
1501: return;
1502: ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
1503: if (ap == NIL)
1504: return;
1505: if (ap->class != ARRAY) {
1506: error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
1507: return;
1508: }
1509: putop( P2LISTOP , P2INT );
1510: al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
1511: if (al->class != ARRAY) {
1512: error("%s requires z to be a packed array, not %s", pu, nameof(ap));
1513: return;
1514: }
1515: if (al->type == NIL || ap->type == NIL)
1516: return;
1517: if (al->type != ap->type) {
1518: error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
1519: return;
1520: }
1521: putop( P2LISTOP , P2INT );
1522: k = width(al);
1523: itemwidth = width(ap->type);
1524: ap = ap->chain;
1525: al = al->chain;
1526: if (ap->chain != NIL || al->chain != NIL) {
1527: error("%s requires a and z to be single dimension arrays", pu);
1528: return;
1529: }
1530: if (ap == NIL || al == NIL)
1531: return;
1532: /*
1533: * al is the range for z i.e. u..v
1534: * ap is the range for a i.e. m..n
1535: * i will be n-m+1
1536: * j will be v-u+1
1537: */
1538: i = ap->range[1] - ap->range[0] + 1;
1539: j = al->range[1] - al->range[0] + 1;
1540: if (i < j) {
1541: error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i);
1542: return;
1543: }
1544: /*
1545: * get n-m-(v-u) and m for the interpreter
1546: */
1547: i -= j;
1548: j = ap->range[0];
1549: putleaf( P2ICON , itemwidth , 0 , P2INT , 0 );
1550: putop( P2LISTOP , P2INT );
1551: putleaf( P2ICON , j , 0 , P2INT , 0 );
1552: putop( P2LISTOP , P2INT );
1553: putleaf( P2ICON , i , 0 , P2INT , 0 );
1554: putop( P2LISTOP , P2INT );
1555: putleaf( P2ICON , k , 0 , P2INT , 0 );
1556: putop( P2LISTOP , P2INT );
1557: putop( P2CALL , P2INT );
1558: putdot( filename , line );
1559: return;
1560: case 0:
1561: error("%s is an unimplemented extension", p->symbol);
1562: return;
1563:
1564: default:
1565: panic("proc case");
1566: }
1567: }
1568: #endif PC
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.