xref: /csrg-svn/usr.bin/pascal/src/proc.c (revision 768)
1*768Speter /* Copyright (c) 1979 Regents of the University of California */
2*768Speter 
3*768Speter static	char sccsid[] = "@(#)proc.c 1.1 08/27/80";
4*768Speter 
5*768Speter #include "whoami.h"
6*768Speter #ifdef OBJ
7*768Speter     /*
8*768Speter      *	and the rest of the file
9*768Speter      */
10*768Speter #include "0.h"
11*768Speter #include "tree.h"
12*768Speter #include "opcode.h"
13*768Speter #include "objfmt.h"
14*768Speter 
15*768Speter /*
16*768Speter  * The following array is used to determine which classes may be read
17*768Speter  * from textfiles. It is indexed by the return value from classify.
18*768Speter  */
19*768Speter #define rdops(x) rdxxxx[(x)-(TFIRST)]
20*768Speter 
21*768Speter int rdxxxx[] = {
22*768Speter 	0,		/* -7 file types */
23*768Speter 	0,		/* -6 record types */
24*768Speter 	0,		/* -5 array types */
25*768Speter 	O_READE,	/* -4 scalar types */
26*768Speter 	0,		/* -3 pointer types */
27*768Speter 	0,		/* -2 set types */
28*768Speter 	0,		/* -1 string types */
29*768Speter 	0,		/*  0 nil, no type */
30*768Speter 	O_READE,	/*  1 boolean */
31*768Speter 	O_READC,	/*  2 character */
32*768Speter 	O_READ4,	/*  3 integer */
33*768Speter 	O_READ8		/*  4 real */
34*768Speter };
35*768Speter 
36*768Speter /*
37*768Speter  * Proc handles procedure calls.
38*768Speter  * Non-builtin procedures are "buck-passed" to func (with a flag
39*768Speter  * indicating that they are actually procedures.
40*768Speter  * builtin procedures are handled here.
41*768Speter  */
42*768Speter proc(r)
43*768Speter 	int *r;
44*768Speter {
45*768Speter 	register struct nl *p;
46*768Speter 	register int *alv, *al, op;
47*768Speter 	struct nl *filetype, *ap;
48*768Speter 	int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file;
49*768Speter 	char fmt, format[20], *strptr;
50*768Speter 	int prec, field, strnglen, fmtlen, fmtstart, pu;
51*768Speter 	int *pua, *pui, *puz;
52*768Speter 	int i, j, k;
53*768Speter 	int itemwidth;
54*768Speter 
55*768Speter #define	CONPREC 4
56*768Speter #define	VARPREC 8
57*768Speter #define	CONWIDTH 1
58*768Speter #define	VARWIDTH 2
59*768Speter #define SKIP 16
60*768Speter 
61*768Speter 	/*
62*768Speter 	 * Verify that the name is
63*768Speter 	 * defined and is that of a
64*768Speter 	 * procedure.
65*768Speter 	 */
66*768Speter 	p = lookup(r[2]);
67*768Speter 	if (p == NIL) {
68*768Speter 		rvlist(r[3]);
69*768Speter 		return;
70*768Speter 	}
71*768Speter 	if (p->class != PROC) {
72*768Speter 		error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
73*768Speter 		rvlist(r[3]);
74*768Speter 		return;
75*768Speter 	}
76*768Speter 	argv = r[3];
77*768Speter 
78*768Speter 	/*
79*768Speter 	 * Call handles user defined
80*768Speter 	 * procedures and functions.
81*768Speter 	 */
82*768Speter 	if (bn != 0) {
83*768Speter 		call(p, argv, PROC, bn);
84*768Speter 		return;
85*768Speter 	}
86*768Speter 
87*768Speter 	/*
88*768Speter 	 * Call to built-in procedure.
89*768Speter 	 * Count the arguments.
90*768Speter 	 */
91*768Speter 	argc = 0;
92*768Speter 	for (al = argv; al != NIL; al = al[2])
93*768Speter 		argc++;
94*768Speter 
95*768Speter 	/*
96*768Speter 	 * Switch on the operator
97*768Speter 	 * associated with the built-in
98*768Speter 	 * procedure in the namelist
99*768Speter 	 */
100*768Speter 	op = p->value[0] &~ NSTAND;
101*768Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
102*768Speter 		standard();
103*768Speter 		error("%s is a nonstandard procedure", p->symbol);
104*768Speter 	}
105*768Speter 	switch (op) {
106*768Speter 
107*768Speter 	case O_ABORT:
108*768Speter 		if (argc != 0)
109*768Speter 			error("null takes no arguments");
110*768Speter 		return;
111*768Speter 
112*768Speter 	case O_FLUSH:
113*768Speter 		if (argc == 0) {
114*768Speter 			put(1, O_MESSAGE);
115*768Speter 			return;
116*768Speter 		}
117*768Speter 		if (argc != 1) {
118*768Speter 			error("flush takes at most one argument");
119*768Speter 			return;
120*768Speter 		}
121*768Speter 		ap = stkrval(argv[1], NIL , RREQ );
122*768Speter 		if (ap == NIL)
123*768Speter 			return;
124*768Speter 		if (ap->class != FILET) {
125*768Speter 			error("flush's argument must be a file, not %s", nameof(ap));
126*768Speter 			return;
127*768Speter 		}
128*768Speter 		put(1, op);
129*768Speter 		return;
130*768Speter 
131*768Speter 	case O_MESSAGE:
132*768Speter 	case O_WRITEF:
133*768Speter 	case O_WRITLN:
134*768Speter 		/*
135*768Speter 		 * Set up default file "output"'s type
136*768Speter 		 */
137*768Speter 		file = NIL;
138*768Speter 		filetype = nl+T1CHAR;
139*768Speter 		/*
140*768Speter 		 * Determine the file implied
141*768Speter 		 * for the write and generate
142*768Speter 		 * code to make it the active file.
143*768Speter 		 */
144*768Speter 		if (op == O_MESSAGE) {
145*768Speter 			/*
146*768Speter 			 * For message, all that matters
147*768Speter 			 * is that the filetype is
148*768Speter 			 * a character file.
149*768Speter 			 * Thus "output" will suit us fine.
150*768Speter 			 */
151*768Speter 			put(1, O_MESSAGE);
152*768Speter 		} else if (argv != NIL && (al = argv[1])[0] != T_WEXP) {
153*768Speter 			/*
154*768Speter 			 * If there is a first argument which has
155*768Speter 			 * no write widths, then it is potentially
156*768Speter 			 * a file name.
157*768Speter 			 */
158*768Speter 			codeoff();
159*768Speter 			ap = stkrval(argv[1], NIL , RREQ );
160*768Speter 			codeon();
161*768Speter 			if (ap == NIL)
162*768Speter 				argv = argv[2];
163*768Speter 			if (ap != NIL && ap->class == FILET) {
164*768Speter 				/*
165*768Speter 				 * Got "write(f, ...", make
166*768Speter 				 * f the active file, and save
167*768Speter 				 * it and its type for use in
168*768Speter 				 * processing the rest of the
169*768Speter 				 * arguments to write.
170*768Speter 				 */
171*768Speter 				file = argv[1];
172*768Speter 				filetype = ap->type;
173*768Speter 				stkrval(argv[1], NIL , RREQ );
174*768Speter 				put(1, O_UNIT);
175*768Speter 				/*
176*768Speter 				 * Skip over the first argument
177*768Speter 				 */
178*768Speter 				argv = argv[2];
179*768Speter 				argc--;
180*768Speter 			} else
181*768Speter 				/*
182*768Speter 				 * Set up for writing on
183*768Speter 				 * standard output.
184*768Speter 				 */
185*768Speter 				put(1, O_UNITOUT);
186*768Speter 		} else
187*768Speter 			put(1, O_UNITOUT);
188*768Speter 		/*
189*768Speter 		 * Loop and process each
190*768Speter 		 * of the arguments.
191*768Speter 		 */
192*768Speter 		for (; argv != NIL; argv = argv[2]) {
193*768Speter 			/*
194*768Speter 			 * fmtspec indicates the type (CONstant or VARiable)
195*768Speter 			 *	and number (none, WIDTH, and/or PRECision)
196*768Speter 			 *	of the fields in the printf format for this
197*768Speter 			 *	output variable.
198*768Speter 			 * stkcnt is the number of longs pushed on the stack
199*768Speter 			 * fmt is the format output indicator (D, E, F, O, X, S)
200*768Speter 			 * fmtstart = 0 for leading blank; = 1 for no blank
201*768Speter 			 */
202*768Speter 			fmtspec = NIL;
203*768Speter 			stkcnt = 0;
204*768Speter 			fmt = 'D';
205*768Speter 			fmtstart = 1;
206*768Speter 			al = argv[1];
207*768Speter 			if (al == NIL)
208*768Speter 				continue;
209*768Speter 			if (al[0] == T_WEXP)
210*768Speter 				alv = al[1];
211*768Speter 			else
212*768Speter 				alv = al;
213*768Speter 			if (alv == NIL)
214*768Speter 				continue;
215*768Speter 			codeoff();
216*768Speter 			ap = stkrval(alv, NIL , RREQ );
217*768Speter 			codeon();
218*768Speter 			if (ap == NIL)
219*768Speter 				continue;
220*768Speter 			typ = classify(ap);
221*768Speter 			if (al[0] == T_WEXP) {
222*768Speter 				/*
223*768Speter 				 * Handle width expressions.
224*768Speter 				 * The basic game here is that width
225*768Speter 				 * expressions get evaluated. If they
226*768Speter 				 * are constant, the value is placed
227*768Speter 				 * directly in the format string.
228*768Speter 				 * Otherwise the value is pushed onto
229*768Speter 				 * the stack and an indirection is
230*768Speter 				 * put into the format string.
231*768Speter 				 */
232*768Speter 				if (al[3] == OCT)
233*768Speter 					fmt = 'O';
234*768Speter 				else if (al[3] == HEX)
235*768Speter 					fmt = 'X';
236*768Speter 				else if (al[3] != NIL) {
237*768Speter 					/*
238*768Speter 					 * Evaluate second format spec
239*768Speter 					 */
240*768Speter 					if ( constval(al[3])
241*768Speter 					    && isa( con.ctype , "i" ) ) {
242*768Speter 						fmtspec += CONPREC;
243*768Speter 						prec = con.crval;
244*768Speter 					} else {
245*768Speter 						fmtspec += VARPREC;
246*768Speter 					}
247*768Speter 					fmt = 'f';
248*768Speter 					switch ( typ ) {
249*768Speter 					case TINT:
250*768Speter 						if ( opt( 's' ) ) {
251*768Speter 						    standard();
252*768Speter 						    error("Writing %ss with two write widths is non-standard", clnames[typ]);
253*768Speter 						}
254*768Speter 						/* and fall through */
255*768Speter 					case TDOUBLE:
256*768Speter 						break;
257*768Speter 					default:
258*768Speter 						error("Cannot write %ss with two write widths", clnames[typ]);
259*768Speter 						continue;
260*768Speter 					}
261*768Speter 				}
262*768Speter 				/*
263*768Speter 				 * Evaluate first format spec
264*768Speter 				 */
265*768Speter 				if (al[2] != NIL) {
266*768Speter 					if ( constval(al[2])
267*768Speter 					    && isa( con.ctype , "i" ) ) {
268*768Speter 						fmtspec += CONWIDTH;
269*768Speter 						field = con.crval;
270*768Speter 					} else {
271*768Speter 						fmtspec += VARWIDTH;
272*768Speter 					}
273*768Speter 				}
274*768Speter 				if ((fmtspec & CONPREC) && prec < 0 ||
275*768Speter 				    (fmtspec & CONWIDTH) && field < 0) {
276*768Speter 					error("Negative widths are not allowed");
277*768Speter 					continue;
278*768Speter 				}
279*768Speter 			}
280*768Speter 			if (filetype != nl+T1CHAR) {
281*768Speter 				if (fmt == 'O' || fmt == 'X') {
282*768Speter 					error("Oct/hex allowed only on text files");
283*768Speter 					continue;
284*768Speter 				}
285*768Speter 				if (fmtspec) {
286*768Speter 					error("Write widths allowed only on text files");
287*768Speter 					continue;
288*768Speter 				}
289*768Speter 				/*
290*768Speter 				 * Generalized write, i.e.
291*768Speter 				 * to a non-textfile.
292*768Speter 				 */
293*768Speter 				stkrval(file, NIL , RREQ );
294*768Speter 				put(1, O_FNIL);
295*768Speter 				/*
296*768Speter 				 * file^ := ...
297*768Speter 				 */
298*768Speter 				ap = rvalue(argv[1], NIL);
299*768Speter 				if (ap == NIL)
300*768Speter 					continue;
301*768Speter 				if (incompat(ap, filetype, argv[1])) {
302*768Speter 					cerror("Type mismatch in write to non-text file");
303*768Speter 					continue;
304*768Speter 				}
305*768Speter 				convert(ap, filetype);
306*768Speter 				put(2, O_AS, width(filetype));
307*768Speter 				/*
308*768Speter 				 * put(file)
309*768Speter 				 */
310*768Speter 				put(1, O_PUT);
311*768Speter 				continue;
312*768Speter 			}
313*768Speter 			/*
314*768Speter 			 * Write to a textfile
315*768Speter 			 *
316*768Speter 			 * Evaluate the expression
317*768Speter 			 * to be written.
318*768Speter 			 */
319*768Speter 			if (fmt == 'O' || fmt == 'X') {
320*768Speter 				if (opt('s')) {
321*768Speter 					standard();
322*768Speter 					error("Oct and hex are non-standard");
323*768Speter 				}
324*768Speter 				if (typ == TSTR || typ == TDOUBLE) {
325*768Speter 					error("Can't write %ss with oct/hex", clnames[typ]);
326*768Speter 					continue;
327*768Speter 				}
328*768Speter 				if (typ == TCHAR || typ == TBOOL)
329*768Speter 					typ = TINT;
330*768Speter 			}
331*768Speter 			/*
332*768Speter 			 * Place the arguement on the stack. If there is
333*768Speter 			 * no format specified by the programmer, implement
334*768Speter 			 * the default.
335*768Speter 			 */
336*768Speter 			switch (typ) {
337*768Speter 			case TINT:
338*768Speter 				if (fmt != 'f') {
339*768Speter 					ap = stkrval(alv, NIL , RREQ );
340*768Speter 					stkcnt++;
341*768Speter 				} else {
342*768Speter 					ap = stkrval(alv, NIL , RREQ );
343*768Speter 					put(1, O_ITOD);
344*768Speter 					stkcnt += 2;
345*768Speter 					typ = TDOUBLE;
346*768Speter 					goto tdouble;
347*768Speter 				}
348*768Speter 				if (fmtspec == NIL) {
349*768Speter 					if (fmt == 'D')
350*768Speter 						field = 10;
351*768Speter 					else if (fmt == 'X')
352*768Speter 						field = 8;
353*768Speter 					else if (fmt == 'O')
354*768Speter 						field = 11;
355*768Speter 					else
356*768Speter 						panic("fmt1");
357*768Speter 					fmtspec = CONWIDTH;
358*768Speter 				}
359*768Speter 				break;
360*768Speter 			case TCHAR:
361*768Speter 			     tchar:
362*768Speter 				ap = stkrval(alv, NIL , RREQ );
363*768Speter 				stkcnt++;
364*768Speter 				fmt = 'c';
365*768Speter 				break;
366*768Speter 			case TSCAL:
367*768Speter 				if (opt('s')) {
368*768Speter 					standard();
369*768Speter 					error("Writing scalars to text files is non-standard");
370*768Speter 				}
371*768Speter 			case TBOOL:
372*768Speter 				stkrval(alv, NIL , RREQ );
373*768Speter 				put(2, O_NAM, listnames(ap));
374*768Speter 				stkcnt++;
375*768Speter 				fmt = 's';
376*768Speter 				break;
377*768Speter 			case TDOUBLE:
378*768Speter 				ap = stkrval(alv, TDOUBLE , RREQ );
379*768Speter 				stkcnt += 2;
380*768Speter 			     tdouble:
381*768Speter 				switch (fmtspec) {
382*768Speter 				case NIL:
383*768Speter 					field = 21;
384*768Speter 					prec = 14;
385*768Speter 					fmt = 'E';
386*768Speter 					fmtspec = CONWIDTH + CONPREC;
387*768Speter 					break;
388*768Speter 				case CONWIDTH:
389*768Speter 					if (--field < 1)
390*768Speter 						field = 1;
391*768Speter 					prec = field - 7;
392*768Speter 					if (prec < 1)
393*768Speter 						prec = 1;
394*768Speter 					fmtspec += CONPREC;
395*768Speter 					fmt = 'E';
396*768Speter 					break;
397*768Speter 				case CONWIDTH + CONPREC:
398*768Speter 				case CONWIDTH + VARPREC:
399*768Speter 					if (--field < 1)
400*768Speter 						field = 1;
401*768Speter 				}
402*768Speter 				format[0] = ' ';
403*768Speter 				fmtstart = 0;
404*768Speter 				break;
405*768Speter 			case TSTR:
406*768Speter 				constval( alv );
407*768Speter 				switch ( classify( con.ctype ) ) {
408*768Speter 				    case TCHAR:
409*768Speter 					typ = TCHAR;
410*768Speter 					goto tchar;
411*768Speter 				    case TSTR:
412*768Speter 					strptr = con.cpval;
413*768Speter 					for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
414*768Speter 					strptr = con.cpval;
415*768Speter 					break;
416*768Speter 				    default:
417*768Speter 					strnglen = width(ap);
418*768Speter 					break;
419*768Speter 				}
420*768Speter 				fmt = 's';
421*768Speter 				strfmt = fmtspec;
422*768Speter 				if (fmtspec == NIL) {
423*768Speter 					fmtspec = SKIP;
424*768Speter 					break;
425*768Speter 				}
426*768Speter 				if (fmtspec & CONWIDTH) {
427*768Speter 					if (field <= strnglen) {
428*768Speter 						fmtspec = SKIP;
429*768Speter 						break;
430*768Speter 					} else
431*768Speter 						field -= strnglen;
432*768Speter 				}
433*768Speter 				/*
434*768Speter 				 * push string to implement leading blank padding
435*768Speter 				 */
436*768Speter 				put(2, O_LVCON, 2);
437*768Speter 				putstr("", 0);
438*768Speter 				stkcnt++;
439*768Speter 				break;
440*768Speter 			default:
441*768Speter 				error("Can't write %ss to a text file", clnames[typ]);
442*768Speter 				continue;
443*768Speter 			}
444*768Speter 			/*
445*768Speter 			 * If there is a variable precision, evaluate it onto
446*768Speter 			 * the stack
447*768Speter 			 */
448*768Speter 			if (fmtspec & VARPREC) {
449*768Speter 				ap = stkrval(al[3], NIL , RREQ );
450*768Speter 				if (ap == NIL)
451*768Speter 					continue;
452*768Speter 				if (isnta(ap,"i")) {
453*768Speter 					error("Second write width must be integer, not %s", nameof(ap));
454*768Speter 					continue;
455*768Speter 				}
456*768Speter 				if ( opt( 't' ) ) {
457*768Speter 				    put(3, O_MAX, 0, 0);
458*768Speter 				}
459*768Speter 				stkcnt++;
460*768Speter 			}
461*768Speter 			/*
462*768Speter 			 * If there is a variable width, evaluate it onto
463*768Speter 			 * the stack
464*768Speter 			 */
465*768Speter 			if (fmtspec & VARWIDTH) {
466*768Speter 				if ( ( typ == TDOUBLE && fmtspec == VARWIDTH )
467*768Speter 				    || typ == TSTR ) {
468*768Speter 					i = sizes[cbn].om_off -= sizeof(int);
469*768Speter 					if (i < sizes[cbn].om_max)
470*768Speter 						sizes[cbn].om_max = i;
471*768Speter 					put(2, O_LV | cbn << 8 + INDX, i);
472*768Speter 				}
473*768Speter 				ap = stkrval(al[2], NIL , RREQ );
474*768Speter 				if (ap == NIL)
475*768Speter 					continue;
476*768Speter 				if (isnta(ap,"i")) {
477*768Speter 					error("First write width must be integer, not %s", nameof(ap));
478*768Speter 					continue;
479*768Speter 				}
480*768Speter 				stkcnt++;
481*768Speter 				/*
482*768Speter 				 * Perform special processing on widths based
483*768Speter 				 * on data type
484*768Speter 				 */
485*768Speter 				switch (typ) {
486*768Speter 				case TDOUBLE:
487*768Speter 					if (fmtspec == VARWIDTH) {
488*768Speter 						fmt = 'E';
489*768Speter 						put(1, O_AS4);
490*768Speter 						put(2, O_RV4 | cbn << 8 + INDX, i);
491*768Speter 						put(3, O_MAX, 8, 1);
492*768Speter 						put(2, O_RV4 | cbn << 8 + INDX, i);
493*768Speter 						stkcnt++;
494*768Speter 						fmtspec += VARPREC;
495*768Speter 					}
496*768Speter 					put(3, O_MAX, 1, 1);
497*768Speter 					break;
498*768Speter 				case TSTR:
499*768Speter 					put(1, O_AS4);
500*768Speter 					put(2, O_RV4 | cbn << 8 + INDX, i);
501*768Speter 					put(3, O_MAX, strnglen, 0);
502*768Speter 					break;
503*768Speter 				default:
504*768Speter 					if ( opt( 't' ) ) {
505*768Speter 					    put(3, O_MAX, 0, 0);
506*768Speter 					}
507*768Speter 					break;
508*768Speter 				}
509*768Speter 			}
510*768Speter 			/*
511*768Speter 			 * Generate the format string
512*768Speter 			 */
513*768Speter 			switch (fmtspec) {
514*768Speter 			default:
515*768Speter 				panic("fmt2");
516*768Speter 			case NIL:
517*768Speter 				if (fmt == 'c')
518*768Speter 					put(1, O_WRITEC);
519*768Speter 				else  {
520*768Speter 					sprintf(&format[1], "%%%c", fmt);
521*768Speter 					goto fmtgen;
522*768Speter 				}
523*768Speter 			case SKIP:
524*768Speter 				break;
525*768Speter 			case CONWIDTH:
526*768Speter 				sprintf(&format[1], "%%%1D%c", field, fmt);
527*768Speter 				goto fmtgen;
528*768Speter 			case VARWIDTH:
529*768Speter 				sprintf(&format[1], "%%*%c", fmt);
530*768Speter 				goto fmtgen;
531*768Speter 			case CONWIDTH + CONPREC:
532*768Speter 				sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt);
533*768Speter 				goto fmtgen;
534*768Speter 			case CONWIDTH + VARPREC:
535*768Speter 				sprintf(&format[1], "%%%1D.*%c", field, fmt);
536*768Speter 				goto fmtgen;
537*768Speter 			case VARWIDTH + CONPREC:
538*768Speter 				sprintf(&format[1], "%%*.%1D%c", prec, fmt);
539*768Speter 				goto fmtgen;
540*768Speter 			case VARWIDTH + VARPREC:
541*768Speter 				sprintf(&format[1], "%%*.*%c", fmt);
542*768Speter 			fmtgen:
543*768Speter 				fmtlen = lenstr(&format[fmtstart], 0);
544*768Speter 				put(2, O_LVCON, fmtlen);
545*768Speter 				putstr(&format[fmtstart], 0);
546*768Speter 				put(1, O_FILE);
547*768Speter 				stkcnt += 2;
548*768Speter 				put(2, O_WRITEF, stkcnt);
549*768Speter 			}
550*768Speter 			/*
551*768Speter 			 * Write the string after its blank padding
552*768Speter 			 */
553*768Speter 			if (typ == TSTR) {
554*768Speter 				put(1, O_FILE);
555*768Speter 				put(2, O_CON24, 1);
556*768Speter 				if (strfmt & VARWIDTH) {
557*768Speter 					put(2, O_RV4 | cbn << 8 + INDX , i );
558*768Speter 					put(2, O_MIN, strnglen);
559*768Speter 				} else {
560*768Speter 					if ((fmtspec & SKIP) &&
561*768Speter 					   (strfmt & CONWIDTH)) {
562*768Speter 						strnglen = field;
563*768Speter 					}
564*768Speter 					put(2, O_CON24, strnglen);
565*768Speter 				}
566*768Speter 				ap = stkrval(alv, NIL , RREQ );
567*768Speter 				put(1, O_WRITES);
568*768Speter 			}
569*768Speter 		}
570*768Speter 		/*
571*768Speter 		 * Done with arguments.
572*768Speter 		 * Handle writeln and
573*768Speter 		 * insufficent number of args.
574*768Speter 		 */
575*768Speter 		switch (p->value[0] &~ NSTAND) {
576*768Speter 			case O_WRITEF:
577*768Speter 				if (argc == 0)
578*768Speter 					error("Write requires an argument");
579*768Speter 				break;
580*768Speter 			case O_MESSAGE:
581*768Speter 				if (argc == 0)
582*768Speter 					error("Message requires an argument");
583*768Speter 			case O_WRITLN:
584*768Speter 				if (filetype != nl+T1CHAR)
585*768Speter 					error("Can't 'writeln' a non text file");
586*768Speter 				put(1, O_WRITLN);
587*768Speter 				break;
588*768Speter 		}
589*768Speter 		return;
590*768Speter 
591*768Speter 	case O_READ4:
592*768Speter 	case O_READLN:
593*768Speter 		/*
594*768Speter 		 * Set up default
595*768Speter 		 * file "input".
596*768Speter 		 */
597*768Speter 		file = NIL;
598*768Speter 		filetype = nl+T1CHAR;
599*768Speter 		/*
600*768Speter 		 * Determine the file implied
601*768Speter 		 * for the read and generate
602*768Speter 		 * code to make it the active file.
603*768Speter 		 */
604*768Speter 		if (argv != NIL) {
605*768Speter 			codeoff();
606*768Speter 			ap = stkrval(argv[1], NIL , RREQ );
607*768Speter 			codeon();
608*768Speter 			if (ap == NIL)
609*768Speter 				argv = argv[2];
610*768Speter 			if (ap != NIL && ap->class == FILET) {
611*768Speter 				/*
612*768Speter 				 * Got "read(f, ...", make
613*768Speter 				 * f the active file, and save
614*768Speter 				 * it and its type for use in
615*768Speter 				 * processing the rest of the
616*768Speter 				 * arguments to read.
617*768Speter 				 */
618*768Speter 				file = argv[1];
619*768Speter 				filetype = ap->type;
620*768Speter 				stkrval(argv[1], NIL , RREQ );
621*768Speter 				put(1, O_UNIT);
622*768Speter 				argv = argv[2];
623*768Speter 				argc--;
624*768Speter 			} else {
625*768Speter 				/*
626*768Speter 				 * Default is read from
627*768Speter 				 * standard input.
628*768Speter 				 */
629*768Speter 				put(1, O_UNITINP);
630*768Speter 				input->nl_flags |= NUSED;
631*768Speter 			}
632*768Speter 		} else {
633*768Speter 			put(1, O_UNITINP);
634*768Speter 			input->nl_flags |= NUSED;
635*768Speter 		}
636*768Speter 		/*
637*768Speter 		 * Loop and process each
638*768Speter 		 * of the arguments.
639*768Speter 		 */
640*768Speter 		for (; argv != NIL; argv = argv[2]) {
641*768Speter 			/*
642*768Speter 			 * Get the address of the target
643*768Speter 			 * on the stack.
644*768Speter 			 */
645*768Speter 			al = argv[1];
646*768Speter 			if (al == NIL)
647*768Speter 				continue;
648*768Speter 			if (al[0] != T_VAR) {
649*768Speter 				error("Arguments to %s must be variables, not expressions", p->symbol);
650*768Speter 				continue;
651*768Speter 			}
652*768Speter 			ap = stklval(al, MOD|ASGN|NOUSE);
653*768Speter 			if (ap == NIL)
654*768Speter 				continue;
655*768Speter 			if (filetype != nl+T1CHAR) {
656*768Speter 				/*
657*768Speter 				 * Generalized read, i.e.
658*768Speter 				 * from a non-textfile.
659*768Speter 				 */
660*768Speter 				if (incompat(filetype, ap, argv[1] )) {
661*768Speter 					error("Type mismatch in read from non-text file");
662*768Speter 					continue;
663*768Speter 				}
664*768Speter 				/*
665*768Speter 				 * var := file ^;
666*768Speter 				 */
667*768Speter 				if (file != NIL)
668*768Speter 					stkrval(file, NIL , RREQ );
669*768Speter 				else /* Magic */
670*768Speter 					put(2, O_RV2, input->value[0]);
671*768Speter 				put(1, O_FNIL);
672*768Speter 				put(2, O_IND, width(filetype));
673*768Speter 				convert(filetype, ap);
674*768Speter 				if (isa(ap, "bsci"))
675*768Speter 					rangechk(ap, ap);
676*768Speter 				put(2, O_AS, width(ap));
677*768Speter 				/*
678*768Speter 				 * get(file);
679*768Speter 				 */
680*768Speter 				put(1, O_GET);
681*768Speter 				continue;
682*768Speter 			}
683*768Speter 			typ = classify(ap);
684*768Speter 			op = rdops(typ);
685*768Speter 			if (op == NIL) {
686*768Speter 				error("Can't read %ss from a text file", clnames[typ]);
687*768Speter 				continue;
688*768Speter 			}
689*768Speter 			if (op != O_READE)
690*768Speter 				put(1, op);
691*768Speter 			else {
692*768Speter 				put(2, op, listnames(ap));
693*768Speter 				if (opt('s')) {
694*768Speter 					standard();
695*768Speter 					error("Reading of enumerated types is non-standard");
696*768Speter 				}
697*768Speter 			}
698*768Speter 			/*
699*768Speter 			 * Data read is on the stack.
700*768Speter 			 * Assign it.
701*768Speter 			 */
702*768Speter 			if (op != O_READ8 && op != O_READE)
703*768Speter 				rangechk(ap, op == O_READC ? ap : nl+T4INT);
704*768Speter 			gen(O_AS2, O_AS2, width(ap),
705*768Speter 				op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2);
706*768Speter 		}
707*768Speter 		/*
708*768Speter 		 * Done with arguments.
709*768Speter 		 * Handle readln and
710*768Speter 		 * insufficient number of args.
711*768Speter 		 */
712*768Speter 		if (p->value[0] == O_READLN) {
713*768Speter 			if (filetype != nl+T1CHAR)
714*768Speter 				error("Can't 'readln' a non text file");
715*768Speter 			put(1, O_READLN);
716*768Speter 		}
717*768Speter 		else if (argc == 0)
718*768Speter 			error("read requires an argument");
719*768Speter 		return;
720*768Speter 
721*768Speter 	case O_GET:
722*768Speter 	case O_PUT:
723*768Speter 		if (argc != 1) {
724*768Speter 			error("%s expects one argument", p->symbol);
725*768Speter 			return;
726*768Speter 		}
727*768Speter 		ap = stkrval(argv[1], NIL , RREQ );
728*768Speter 		if (ap == NIL)
729*768Speter 			return;
730*768Speter 		if (ap->class != FILET) {
731*768Speter 			error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
732*768Speter 			return;
733*768Speter 		}
734*768Speter 		put(1, O_UNIT);
735*768Speter 		put(1, op);
736*768Speter 		return;
737*768Speter 
738*768Speter 	case O_RESET:
739*768Speter 	case O_REWRITE:
740*768Speter 		if (argc == 0 || argc > 2) {
741*768Speter 			error("%s expects one or two arguments", p->symbol);
742*768Speter 			return;
743*768Speter 		}
744*768Speter 		if (opt('s') && argc == 2) {
745*768Speter 			standard();
746*768Speter 			error("Two argument forms of reset and rewrite are non-standard");
747*768Speter 		}
748*768Speter 		ap = stklval(argv[1], MOD|NOUSE);
749*768Speter 		if (ap == NIL)
750*768Speter 			return;
751*768Speter 		if (ap->class != FILET) {
752*768Speter 			error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
753*768Speter 			return;
754*768Speter 		}
755*768Speter 		if (argc == 2) {
756*768Speter 			/*
757*768Speter 			 * Optional second argument
758*768Speter 			 * is a string name of a
759*768Speter 			 * UNIX (R) file to be associated.
760*768Speter 			 */
761*768Speter 			al = argv[2];
762*768Speter 			al = stkrval(al[1], NOFLAGS , RREQ );
763*768Speter 			if (al == NIL)
764*768Speter 				return;
765*768Speter 			if (classify(al) != TSTR) {
766*768Speter 				error("Second argument to %s must be a string, not %s", p->symbol, nameof(al));
767*768Speter 				return;
768*768Speter 			}
769*768Speter 			strnglen = width(al);
770*768Speter 		} else {
771*768Speter 			put(2, O_CON24, NIL);
772*768Speter 			strnglen = 0;
773*768Speter 		}
774*768Speter 		put(2, O_CON24, strnglen);
775*768Speter 		put(2, O_CON24, text(ap) ? 0: width(ap->type));
776*768Speter 		put(1, op);
777*768Speter 		return;
778*768Speter 
779*768Speter 	case O_NEW:
780*768Speter 	case O_DISPOSE:
781*768Speter 		if (argc == 0) {
782*768Speter 			error("%s expects at least one argument", p->symbol);
783*768Speter 			return;
784*768Speter 		}
785*768Speter 		ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD );
786*768Speter 		if (ap == NIL)
787*768Speter 			return;
788*768Speter 		if (ap->class != PTR) {
789*768Speter 			error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
790*768Speter 			return;
791*768Speter 		}
792*768Speter 		ap = ap->type;
793*768Speter 		if (ap == NIL)
794*768Speter 			return;
795*768Speter 		argv = argv[2];
796*768Speter 		if (argv != NIL) {
797*768Speter 			if (ap->class != RECORD) {
798*768Speter 				error("Record required when specifying variant tags");
799*768Speter 				return;
800*768Speter 			}
801*768Speter 			for (; argv != NIL; argv = argv[2]) {
802*768Speter 				if (ap->ptr[NL_VARNT] == NIL) {
803*768Speter 					error("Too many tag fields");
804*768Speter 					return;
805*768Speter 				}
806*768Speter 				if (!isconst(argv[1])) {
807*768Speter 					error("Second and successive arguments to %s must be constants", p->symbol);
808*768Speter 					return;
809*768Speter 				}
810*768Speter 				gconst(argv[1]);
811*768Speter 				if (con.ctype == NIL)
812*768Speter 					return;
813*768Speter 				if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) {
814*768Speter 					cerror("Specified tag constant type clashed with variant case selector type");
815*768Speter 					return;
816*768Speter 				}
817*768Speter 				for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
818*768Speter 					if (ap->range[0] == con.crval)
819*768Speter 						break;
820*768Speter 				if (ap == NIL) {
821*768Speter 					error("No variant case label value equals specified constant value");
822*768Speter 					return;
823*768Speter 				}
824*768Speter 				ap = ap->ptr[NL_VTOREC];
825*768Speter 			}
826*768Speter 		}
827*768Speter 		put(2, op, width(ap));
828*768Speter 		return;
829*768Speter 
830*768Speter 	case O_DATE:
831*768Speter 	case O_TIME:
832*768Speter 		if (argc != 1) {
833*768Speter 			error("%s expects one argument", p->symbol);
834*768Speter 			return;
835*768Speter 		}
836*768Speter 		ap = stklval(argv[1], MOD|NOUSE);
837*768Speter 		if (ap == NIL)
838*768Speter 			return;
839*768Speter 		if (classify(ap) != TSTR || width(ap) != 10) {
840*768Speter 			error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
841*768Speter 			return;
842*768Speter 		}
843*768Speter 		put(1, op);
844*768Speter 		return;
845*768Speter 
846*768Speter 	case O_HALT:
847*768Speter 		if (argc != 0) {
848*768Speter 			error("halt takes no arguments");
849*768Speter 			return;
850*768Speter 		}
851*768Speter 		put(1, op);
852*768Speter 		noreach = 1;
853*768Speter 		return;
854*768Speter 
855*768Speter 	case O_ARGV:
856*768Speter 		if (argc != 2) {
857*768Speter 			error("argv takes two arguments");
858*768Speter 			return;
859*768Speter 		}
860*768Speter 		ap = stkrval(argv[1], NIL , RREQ );
861*768Speter 		if (ap == NIL)
862*768Speter 			return;
863*768Speter 		if (isnta(ap, "i")) {
864*768Speter 			error("argv's first argument must be an integer, not %s", nameof(ap));
865*768Speter 			return;
866*768Speter 		}
867*768Speter 		al = argv[2];
868*768Speter 		ap = stklval(al[1], MOD|NOUSE);
869*768Speter 		if (ap == NIL)
870*768Speter 			return;
871*768Speter 		if (classify(ap) != TSTR) {
872*768Speter 			error("argv's second argument must be a string, not %s", nameof(ap));
873*768Speter 			return;
874*768Speter 		}
875*768Speter 		put(2, op, width(ap));
876*768Speter 		return;
877*768Speter 
878*768Speter 	case O_STLIM:
879*768Speter 		if (argc != 1) {
880*768Speter 			error("stlimit requires one argument");
881*768Speter 			return;
882*768Speter 		}
883*768Speter 		ap = stkrval(argv[1], NIL , RREQ );
884*768Speter 		if (ap == NIL)
885*768Speter 			return;
886*768Speter 		if (isnta(ap, "i")) {
887*768Speter 			error("stlimit's argument must be an integer, not %s", nameof(ap));
888*768Speter 			return;
889*768Speter 		}
890*768Speter 		if (width(ap) != 4)
891*768Speter 			put(1, O_STOI);
892*768Speter 		put(1, op);
893*768Speter 		return;
894*768Speter 
895*768Speter 	case O_REMOVE:
896*768Speter 		if (argc != 1) {
897*768Speter 			error("remove expects one argument");
898*768Speter 			return;
899*768Speter 		}
900*768Speter 		ap = stkrval(argv[1], NOFLAGS , RREQ );
901*768Speter 		if (ap == NIL)
902*768Speter 			return;
903*768Speter 		if (classify(ap) != TSTR) {
904*768Speter 			error("remove's argument must be a string, not %s", nameof(ap));
905*768Speter 			return;
906*768Speter 		}
907*768Speter 		put(2, O_CON24, width(ap));
908*768Speter 		put(1, op);
909*768Speter 		return;
910*768Speter 
911*768Speter 	case O_LLIMIT:
912*768Speter 		if (argc != 2) {
913*768Speter 			error("linelimit expects two arguments");
914*768Speter 			return;
915*768Speter 		}
916*768Speter 		ap = stklval(argv[1], NOFLAGS|NOUSE);
917*768Speter 		if (ap == NIL)
918*768Speter 			return;
919*768Speter 		if (!text(ap)) {
920*768Speter 			error("linelimit's first argument must be a text file, not %s", nameof(ap));
921*768Speter 			return;
922*768Speter 		}
923*768Speter 		al = argv[2];
924*768Speter 		ap = stkrval(al[1], NIL , RREQ );
925*768Speter 		if (ap == NIL)
926*768Speter 			return;
927*768Speter 		if (isnta(ap, "i")) {
928*768Speter 			error("linelimit's second argument must be an integer, not %s", nameof(ap));
929*768Speter 			return;
930*768Speter 		}
931*768Speter 		put(1, op);
932*768Speter 		return;
933*768Speter 	case O_PAGE:
934*768Speter 		if (argc != 1) {
935*768Speter 			error("page expects one argument");
936*768Speter 			return;
937*768Speter 		}
938*768Speter 		ap = stkrval(argv[1], NIL , RREQ );
939*768Speter 		if (ap == NIL)
940*768Speter 			return;
941*768Speter 		if (!text(ap)) {
942*768Speter 			error("Argument to page must be a text file, not %s", nameof(ap));
943*768Speter 			return;
944*768Speter 		}
945*768Speter 		put(1, O_UNIT);
946*768Speter 		put(1, op);
947*768Speter 		return;
948*768Speter 
949*768Speter 	case O_PACK:
950*768Speter 		if (argc != 3) {
951*768Speter 			error("pack expects three arguments");
952*768Speter 			return;
953*768Speter 		}
954*768Speter 		pu = "pack(a,i,z)";
955*768Speter 		pua = (al = argv)[1];
956*768Speter 		pui = (al = al[2])[1];
957*768Speter 		puz = (al = al[2])[1];
958*768Speter 		goto packunp;
959*768Speter 	case O_UNPACK:
960*768Speter 		if (argc != 3) {
961*768Speter 			error("unpack expects three arguments");
962*768Speter 			return;
963*768Speter 		}
964*768Speter 		pu = "unpack(z,a,i)";
965*768Speter 		puz = (al = argv)[1];
966*768Speter 		pua = (al = al[2])[1];
967*768Speter 		pui = (al = al[2])[1];
968*768Speter packunp:
969*768Speter 		ap = stkrval((int *) pui, NLNIL , RREQ );
970*768Speter 		if (ap == NIL)
971*768Speter 			return;
972*768Speter 		ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
973*768Speter 		if (ap == NIL)
974*768Speter 			return;
975*768Speter 		if (ap->class != ARRAY) {
976*768Speter 			error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
977*768Speter 			return;
978*768Speter 		}
979*768Speter 		al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
980*768Speter 		if (al->class != ARRAY) {
981*768Speter 			error("%s requires z to be a packed array, not %s", pu, nameof(ap));
982*768Speter 			return;
983*768Speter 		}
984*768Speter 		if (al->type == NIL || ap->type == NIL)
985*768Speter 			return;
986*768Speter 		if (al->type != ap->type) {
987*768Speter 			error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
988*768Speter 			return;
989*768Speter 		}
990*768Speter 		k = width(al);
991*768Speter 		itemwidth = width(ap->type);
992*768Speter 		ap = ap->chain;
993*768Speter 		al = al->chain;
994*768Speter 		if (ap->chain != NIL || al->chain != NIL) {
995*768Speter 			error("%s requires a and z to be single dimension arrays", pu);
996*768Speter 			return;
997*768Speter 		}
998*768Speter 		if (ap == NIL || al == NIL)
999*768Speter 			return;
1000*768Speter 		/*
1001*768Speter 		 * al is the range for z i.e. u..v
1002*768Speter 		 * ap is the range for a i.e. m..n
1003*768Speter 		 * i will be n-m+1
1004*768Speter 		 * j will be v-u+1
1005*768Speter 		 */
1006*768Speter 		i = ap->range[1] - ap->range[0] + 1;
1007*768Speter 		j = al->range[1] - al->range[0] + 1;
1008*768Speter 		if (i < j) {
1009*768Speter 			error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i);
1010*768Speter 			return;
1011*768Speter 		}
1012*768Speter 		/*
1013*768Speter 		 * get n-m-(v-u) and m for the interpreter
1014*768Speter 		 */
1015*768Speter 		i -= j;
1016*768Speter 		j = ap->range[0];
1017*768Speter 		put(5, op, itemwidth , j, i, k);
1018*768Speter 		return;
1019*768Speter 	case 0:
1020*768Speter 		error("%s is an unimplemented 6400 extension", p->symbol);
1021*768Speter 		return;
1022*768Speter 
1023*768Speter 	default:
1024*768Speter 		panic("proc case");
1025*768Speter 	}
1026*768Speter }
1027*768Speter #endif OBJ
1028