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