date and time created 80/08/27 19:56:02 by peter
authorPeter B. Kessler <peter@ucbvax.Berkeley.EDU>
Thu, 28 Aug 1980 10:56:02 +0000 (02:56 -0800)
committerPeter B. Kessler <peter@ucbvax.Berkeley.EDU>
Thu, 28 Aug 1980 10:56:02 +0000 (02:56 -0800)
SCCS-vsn: usr.bin/pascal/src/proc.c 1.1

usr/src/usr.bin/pascal/src/proc.c [new file with mode: 0644]

diff --git a/usr/src/usr.bin/pascal/src/proc.c b/usr/src/usr.bin/pascal/src/proc.c
new file mode 100644 (file)
index 0000000..5076f8c
--- /dev/null
@@ -0,0 +1,1027 @@
+/* Copyright (c) 1979 Regents of the University of California */
+
+static char sccsid[] = "@(#)proc.c 1.1 %G%";
+
+#include "whoami.h"
+#ifdef OBJ
+    /*
+     * and the rest of the file
+     */
+#include "0.h"
+#include "tree.h"
+#include "opcode.h"
+#include "objfmt.h"
+
+/*
+ * The following array is used to determine which classes may be read
+ * from textfiles. It is indexed by the return value from classify.
+ */
+#define rdops(x) rdxxxx[(x)-(TFIRST)]
+
+int rdxxxx[] = {
+       0,              /* -7 file types */
+       0,              /* -6 record types */
+       0,              /* -5 array types */
+       O_READE,        /* -4 scalar types */
+       0,              /* -3 pointer types */
+       0,              /* -2 set types */
+       0,              /* -1 string types */
+       0,              /*  0 nil, no type */
+       O_READE,        /*  1 boolean */
+       O_READC,        /*  2 character */
+       O_READ4,        /*  3 integer */
+       O_READ8         /*  4 real */
+};
+\f
+/*
+ * Proc handles procedure calls.
+ * Non-builtin procedures are "buck-passed" to func (with a flag
+ * indicating that they are actually procedures.
+ * builtin procedures are handled here.
+ */
+proc(r)
+       int *r;
+{
+       register struct nl *p;
+       register int *alv, *al, op;
+       struct nl *filetype, *ap;
+       int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file;
+       char fmt, format[20], *strptr;
+       int prec, field, strnglen, fmtlen, fmtstart, pu;
+       int *pua, *pui, *puz;
+       int i, j, k;
+       int itemwidth;
+
+#define        CONPREC 4
+#define        VARPREC 8
+#define        CONWIDTH 1
+#define        VARWIDTH 2
+#define SKIP 16
+
+       /*
+        * Verify that the name is
+        * defined and is that of a
+        * procedure.
+        */
+       p = lookup(r[2]);
+       if (p == NIL) {
+               rvlist(r[3]);
+               return;
+       }
+       if (p->class != PROC) {
+               error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
+               rvlist(r[3]);
+               return;
+       }
+       argv = r[3];
+
+       /*
+        * Call handles user defined
+        * procedures and functions.
+        */
+       if (bn != 0) {
+               call(p, argv, PROC, bn);
+               return;
+       }
+
+       /*
+        * Call to built-in procedure.
+        * Count the arguments.
+        */
+       argc = 0;
+       for (al = argv; al != NIL; al = al[2])
+               argc++;
+
+       /*
+        * Switch on the operator
+        * associated with the built-in
+        * procedure in the namelist
+        */
+       op = p->value[0] &~ NSTAND;
+       if (opt('s') && (p->value[0] & NSTAND)) {
+               standard();
+               error("%s is a nonstandard procedure", p->symbol);
+       }
+       switch (op) {
+
+       case O_ABORT:
+               if (argc != 0)
+                       error("null takes no arguments");
+               return;
+
+       case O_FLUSH:
+               if (argc == 0) {
+                       put(1, O_MESSAGE);
+                       return;
+               }
+               if (argc != 1) {
+                       error("flush takes at most one argument");
+                       return;
+               }
+               ap = stkrval(argv[1], NIL , RREQ );
+               if (ap == NIL)
+                       return;
+               if (ap->class != FILET) {
+                       error("flush's argument must be a file, not %s", nameof(ap));
+                       return;
+               }
+               put(1, op);
+               return;
+
+       case O_MESSAGE:
+       case O_WRITEF:
+       case O_WRITLN:
+               /*
+                * Set up default file "output"'s type
+                */
+               file = NIL;
+               filetype = nl+T1CHAR;
+               /*
+                * Determine the file implied
+                * for the write and generate
+                * code to make it the active file.
+                */
+               if (op == O_MESSAGE) {
+                       /*
+                        * For message, all that matters
+                        * is that the filetype is
+                        * a character file.
+                        * Thus "output" will suit us fine.
+                        */
+                       put(1, O_MESSAGE);
+               } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) {
+                       /*
+                        * If there is a first argument which has
+                        * no write widths, then it is potentially
+                        * a file name.
+                        */
+                       codeoff();
+                       ap = stkrval(argv[1], NIL , RREQ );
+                       codeon();
+                       if (ap == NIL)
+                               argv = argv[2];
+                       if (ap != NIL && ap->class == FILET) {
+                               /*
+                                * Got "write(f, ...", make
+                                * f the active file, and save
+                                * it and its type for use in
+                                * processing the rest of the
+                                * arguments to write.
+                                */
+                               file = argv[1];
+                               filetype = ap->type;
+                               stkrval(argv[1], NIL , RREQ );
+                               put(1, O_UNIT);
+                               /*
+                                * Skip over the first argument
+                                */
+                               argv = argv[2];
+                               argc--;
+                       } else
+                               /*
+                                * Set up for writing on 
+                                * standard output.
+                                */
+                               put(1, O_UNITOUT);
+               } else
+                       put(1, O_UNITOUT);
+               /*
+                * Loop and process each
+                * of the arguments.
+                */
+               for (; argv != NIL; argv = argv[2]) {
+                       /*
+                        * fmtspec indicates the type (CONstant or VARiable)
+                        *      and number (none, WIDTH, and/or PRECision)
+                        *      of the fields in the printf format for this
+                        *      output variable.
+                        * stkcnt is the number of longs pushed on the stack
+                        * fmt is the format output indicator (D, E, F, O, X, S)
+                        * fmtstart = 0 for leading blank; = 1 for no blank
+                        */
+                       fmtspec = NIL;
+                       stkcnt = 0;
+                       fmt = 'D';
+                       fmtstart = 1;
+                       al = argv[1];
+                       if (al == NIL)
+                               continue;
+                       if (al[0] == T_WEXP)
+                               alv = al[1];
+                       else
+                               alv = al;
+                       if (alv == NIL)
+                               continue;
+                       codeoff();
+                       ap = stkrval(alv, NIL , RREQ );
+                       codeon();
+                       if (ap == NIL)
+                               continue;
+                       typ = classify(ap);
+                       if (al[0] == T_WEXP) {
+                               /*
+                                * Handle width expressions.
+                                * The basic game here is that width
+                                * expressions get evaluated. If they
+                                * are constant, the value is placed
+                                * directly in the format string.
+                                * Otherwise the value is pushed onto
+                                * the stack and an indirection is
+                                * put into the format string.
+                                */
+                               if (al[3] == OCT)
+                                       fmt = 'O';
+                               else if (al[3] == HEX)
+                                       fmt = 'X';
+                               else if (al[3] != NIL) {
+                                       /*
+                                        * Evaluate second format spec
+                                        */
+                                       if ( constval(al[3])
+                                           && isa( con.ctype , "i" ) ) {
+                                               fmtspec += CONPREC;
+                                               prec = con.crval;
+                                       } else {
+                                               fmtspec += VARPREC;
+                                       }
+                                       fmt = 'f';
+                                       switch ( typ ) {
+                                       case TINT:
+                                               if ( opt( 's' ) ) {
+                                                   standard();
+                                                   error("Writing %ss with two write widths is non-standard", clnames[typ]);
+                                               }
+                                               /* and fall through */
+                                       case TDOUBLE:
+                                               break;
+                                       default:
+                                               error("Cannot write %ss with two write widths", clnames[typ]);
+                                               continue;
+                                       }
+                               }
+                               /*
+                                * Evaluate first format spec
+                                */
+                               if (al[2] != NIL) {
+                                       if ( constval(al[2])
+                                           && isa( con.ctype , "i" ) ) {
+                                               fmtspec += CONWIDTH;
+                                               field = con.crval;
+                                       } else {
+                                               fmtspec += VARWIDTH;
+                                       }
+                               }
+                               if ((fmtspec & CONPREC) && prec < 0 ||
+                                   (fmtspec & CONWIDTH) && field < 0) {
+                                       error("Negative widths are not allowed");
+                                       continue;
+                               }
+                       }
+                       if (filetype != nl+T1CHAR) {
+                               if (fmt == 'O' || fmt == 'X') {
+                                       error("Oct/hex allowed only on text files");
+                                       continue;
+                               }
+                               if (fmtspec) {
+                                       error("Write widths allowed only on text files");
+                                       continue;
+                               }
+                               /*
+                                * Generalized write, i.e.
+                                * to a non-textfile.
+                                */
+                               stkrval(file, NIL , RREQ );
+                               put(1, O_FNIL);
+                               /*
+                                * file^ := ...
+                                */
+                               ap = rvalue(argv[1], NIL);
+                               if (ap == NIL)
+                                       continue;
+                               if (incompat(ap, filetype, argv[1])) {
+                                       cerror("Type mismatch in write to non-text file");
+                                       continue;
+                               }
+                               convert(ap, filetype);
+                               put(2, O_AS, width(filetype));
+                               /*
+                                * put(file)
+                                */
+                               put(1, O_PUT);
+                               continue;
+                       }
+                       /*
+                        * Write to a textfile
+                        *
+                        * Evaluate the expression
+                        * to be written.
+                        */
+                       if (fmt == 'O' || fmt == 'X') {
+                               if (opt('s')) {
+                                       standard();
+                                       error("Oct and hex are non-standard");
+                               }
+                               if (typ == TSTR || typ == TDOUBLE) {
+                                       error("Can't write %ss with oct/hex", clnames[typ]);
+                                       continue;
+                               }
+                               if (typ == TCHAR || typ == TBOOL)
+                                       typ = TINT;
+                       }
+                       /*
+                        * Place the arguement on the stack. If there is
+                        * no format specified by the programmer, implement
+                        * the default.
+                        */
+                       switch (typ) {
+                       case TINT:
+                               if (fmt != 'f') {
+                                       ap = stkrval(alv, NIL , RREQ );
+                                       stkcnt++;
+                               } else {
+                                       ap = stkrval(alv, NIL , RREQ );
+                                       put(1, O_ITOD);
+                                       stkcnt += 2;
+                                       typ = TDOUBLE;
+                                       goto tdouble;
+                               }
+                               if (fmtspec == NIL) {
+                                       if (fmt == 'D')
+                                               field = 10;
+                                       else if (fmt == 'X')
+                                               field = 8;
+                                       else if (fmt == 'O')
+                                               field = 11;
+                                       else
+                                               panic("fmt1");
+                                       fmtspec = CONWIDTH;
+                               }
+                               break;
+                       case TCHAR:
+                            tchar:
+                               ap = stkrval(alv, NIL , RREQ );
+                               stkcnt++;
+                               fmt = 'c';
+                               break;
+                       case TSCAL:
+                               if (opt('s')) {
+                                       standard();
+                                       error("Writing scalars to text files is non-standard");
+                               }
+                       case TBOOL:
+                               stkrval(alv, NIL , RREQ );
+                               put(2, O_NAM, listnames(ap));
+                               stkcnt++;
+                               fmt = 's';
+                               break;
+                       case TDOUBLE:
+                               ap = stkrval(alv, TDOUBLE , RREQ );
+                               stkcnt += 2;
+                            tdouble:
+                               switch (fmtspec) {
+                               case NIL:
+                                       field = 21;
+                                       prec = 14;
+                                       fmt = 'E';
+                                       fmtspec = CONWIDTH + CONPREC;
+                                       break;
+                               case CONWIDTH:
+                                       if (--field < 1)
+                                               field = 1;
+                                       prec = field - 7;
+                                       if (prec < 1)
+                                               prec = 1;
+                                       fmtspec += CONPREC;
+                                       fmt = 'E';
+                                       break;
+                               case CONWIDTH + CONPREC:
+                               case CONWIDTH + VARPREC:
+                                       if (--field < 1)
+                                               field = 1;
+                               }
+                               format[0] = ' ';
+                               fmtstart = 0;
+                               break;
+                       case TSTR:
+                               constval( alv );
+                               switch ( classify( con.ctype ) ) {
+                                   case TCHAR:
+                                       typ = TCHAR;
+                                       goto tchar;
+                                   case TSTR:
+                                       strptr = con.cpval;
+                                       for (strnglen = 0;  *strptr++;  strnglen++) /* void */;
+                                       strptr = con.cpval;
+                                       break;
+                                   default:
+                                       strnglen = width(ap);
+                                       break;
+                               }
+                               fmt = 's';
+                               strfmt = fmtspec;
+                               if (fmtspec == NIL) {
+                                       fmtspec = SKIP;
+                                       break;
+                               }
+                               if (fmtspec & CONWIDTH) {
+                                       if (field <= strnglen) {
+                                               fmtspec = SKIP;
+                                               break;
+                                       } else
+                                               field -= strnglen;
+                               }
+                               /*
+                                * push string to implement leading blank padding
+                                */
+                               put(2, O_LVCON, 2);
+                               putstr("", 0);
+                               stkcnt++;
+                               break;
+                       default:
+                               error("Can't write %ss to a text file", clnames[typ]);
+                               continue;
+                       }
+                       /*
+                        * If there is a variable precision, evaluate it onto
+                        * the stack
+                        */
+                       if (fmtspec & VARPREC) {
+                               ap = stkrval(al[3], NIL , RREQ );
+                               if (ap == NIL)
+                                       continue;
+                               if (isnta(ap,"i")) {
+                                       error("Second write width must be integer, not %s", nameof(ap));
+                                       continue;
+                               }
+                               if ( opt( 't' ) ) {
+                                   put(3, O_MAX, 0, 0);
+                               }
+                               stkcnt++;
+                       }
+                       /*
+                        * If there is a variable width, evaluate it onto
+                        * the stack
+                        */
+                       if (fmtspec & VARWIDTH) {
+                               if ( ( typ == TDOUBLE && fmtspec == VARWIDTH )
+                                   || typ == TSTR ) {
+                                       i = sizes[cbn].om_off -= sizeof(int);
+                                       if (i < sizes[cbn].om_max)
+                                               sizes[cbn].om_max = i;
+                                       put(2, O_LV | cbn << 8 + INDX, i);
+                               }
+                               ap = stkrval(al[2], NIL , RREQ );
+                               if (ap == NIL)
+                                       continue;
+                               if (isnta(ap,"i")) {
+                                       error("First write width must be integer, not %s", nameof(ap));
+                                       continue;
+                               }
+                               stkcnt++;
+                               /*
+                                * Perform special processing on widths based
+                                * on data type 
+                                */
+                               switch (typ) {
+                               case TDOUBLE:
+                                       if (fmtspec == VARWIDTH) {
+                                               fmt = 'E';
+                                               put(1, O_AS4);
+                                               put(2, O_RV4 | cbn << 8 + INDX, i);
+                                               put(3, O_MAX, 8, 1);
+                                               put(2, O_RV4 | cbn << 8 + INDX, i);
+                                               stkcnt++;
+                                               fmtspec += VARPREC;
+                                       }
+                                       put(3, O_MAX, 1, 1);
+                                       break;
+                               case TSTR:
+                                       put(1, O_AS4);
+                                       put(2, O_RV4 | cbn << 8 + INDX, i);
+                                       put(3, O_MAX, strnglen, 0);
+                                       break;
+                               default:
+                                       if ( opt( 't' ) ) {
+                                           put(3, O_MAX, 0, 0);
+                                       }
+                                       break;
+                               }
+                       }
+                       /*
+                        * Generate the format string
+                        */
+                       switch (fmtspec) {
+                       default:
+                               panic("fmt2");
+                       case NIL:
+                               if (fmt == 'c')
+                                       put(1, O_WRITEC);
+                               else  {
+                                       sprintf(&format[1], "%%%c", fmt);
+                                       goto fmtgen;
+                               }
+                       case SKIP:
+                               break;
+                       case CONWIDTH:
+                               sprintf(&format[1], "%%%1D%c", field, fmt);
+                               goto fmtgen;
+                       case VARWIDTH:
+                               sprintf(&format[1], "%%*%c", fmt);
+                               goto fmtgen;
+                       case CONWIDTH + CONPREC:
+                               sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt);
+                               goto fmtgen;
+                       case CONWIDTH + VARPREC:
+                               sprintf(&format[1], "%%%1D.*%c", field, fmt);
+                               goto fmtgen;
+                       case VARWIDTH + CONPREC:
+                               sprintf(&format[1], "%%*.%1D%c", prec, fmt);
+                               goto fmtgen;
+                       case VARWIDTH + VARPREC:
+                               sprintf(&format[1], "%%*.*%c", fmt);
+                       fmtgen:
+                               fmtlen = lenstr(&format[fmtstart], 0);
+                               put(2, O_LVCON, fmtlen);
+                               putstr(&format[fmtstart], 0);
+                               put(1, O_FILE);
+                               stkcnt += 2;
+                               put(2, O_WRITEF, stkcnt);
+                       }
+                       /*
+                        * Write the string after its blank padding
+                        */
+                       if (typ == TSTR) {
+                               put(1, O_FILE);
+                               put(2, O_CON24, 1);
+                               if (strfmt & VARWIDTH) {
+                                       put(2, O_RV4 | cbn << 8 + INDX , i );
+                                       put(2, O_MIN, strnglen);
+                               } else {
+                                       if ((fmtspec & SKIP) &&
+                                          (strfmt & CONWIDTH)) {
+                                               strnglen = field;
+                                       }
+                                       put(2, O_CON24, strnglen);
+                               }
+                               ap = stkrval(alv, NIL , RREQ );
+                               put(1, O_WRITES);
+                       }
+               }
+               /*
+                * Done with arguments.
+                * Handle writeln and
+                * insufficent number of args.
+                */
+               switch (p->value[0] &~ NSTAND) {
+                       case O_WRITEF:
+                               if (argc == 0)
+                                       error("Write requires an argument");
+                               break;
+                       case O_MESSAGE:
+                               if (argc == 0)
+                                       error("Message requires an argument");
+                       case O_WRITLN:
+                               if (filetype != nl+T1CHAR)
+                                       error("Can't 'writeln' a non text file");
+                               put(1, O_WRITLN);
+                               break;
+               }
+               return;
+
+       case O_READ4:
+       case O_READLN:
+               /*
+                * Set up default
+                * file "input".
+                */
+               file = NIL;
+               filetype = nl+T1CHAR;
+               /*
+                * Determine the file implied
+                * for the read and generate
+                * code to make it the active file.
+                */
+               if (argv != NIL) {
+                       codeoff();
+                       ap = stkrval(argv[1], NIL , RREQ );
+                       codeon();
+                       if (ap == NIL)
+                               argv = argv[2];
+                       if (ap != NIL && ap->class == FILET) {
+                               /*
+                                * Got "read(f, ...", make
+                                * f the active file, and save
+                                * it and its type for use in
+                                * processing the rest of the
+                                * arguments to read.
+                                */
+                               file = argv[1];
+                               filetype = ap->type;
+                               stkrval(argv[1], NIL , RREQ );
+                               put(1, O_UNIT);
+                               argv = argv[2];
+                               argc--;
+                       } else {
+                               /*
+                                * Default is read from
+                                * standard input.
+                                */
+                               put(1, O_UNITINP);
+                               input->nl_flags |= NUSED;
+                       }
+               } else {
+                       put(1, O_UNITINP);
+                       input->nl_flags |= NUSED;
+               }
+               /*
+                * Loop and process each
+                * of the arguments.
+                */
+               for (; argv != NIL; argv = argv[2]) {
+                       /*
+                        * Get the address of the target
+                        * on the stack.
+                        */
+                       al = argv[1];
+                       if (al == NIL)
+                               continue;
+                       if (al[0] != T_VAR) {
+                               error("Arguments to %s must be variables, not expressions", p->symbol);
+                               continue;
+                       }
+                       ap = stklval(al, MOD|ASGN|NOUSE);
+                       if (ap == NIL)
+                               continue;
+                       if (filetype != nl+T1CHAR) {
+                               /*
+                                * Generalized read, i.e.
+                                * from a non-textfile.
+                                */
+                               if (incompat(filetype, ap, argv[1] )) {
+                                       error("Type mismatch in read from non-text file");
+                                       continue;
+                               }
+                               /*
+                                * var := file ^;
+                                */
+                               if (file != NIL)
+                                       stkrval(file, NIL , RREQ );
+                               else /* Magic */
+                                       put(2, O_RV2, input->value[0]);
+                               put(1, O_FNIL);
+                               put(2, O_IND, width(filetype));
+                               convert(filetype, ap);
+                               if (isa(ap, "bsci"))
+                                       rangechk(ap, ap);
+                               put(2, O_AS, width(ap));
+                               /*
+                                * get(file);
+                                */
+                               put(1, O_GET);
+                               continue;
+                       }
+                       typ = classify(ap);
+                       op = rdops(typ);
+                       if (op == NIL) {
+                               error("Can't read %ss from a text file", clnames[typ]);
+                               continue;
+                       }
+                       if (op != O_READE)
+                               put(1, op);
+                       else {
+                               put(2, op, listnames(ap));
+                               if (opt('s')) {
+                                       standard();
+                                       error("Reading of enumerated types is non-standard");
+                               }
+                       }
+                       /*
+                        * Data read is on the stack.
+                        * Assign it.
+                        */
+                       if (op != O_READ8 && op != O_READE)
+                               rangechk(ap, op == O_READC ? ap : nl+T4INT);
+                       gen(O_AS2, O_AS2, width(ap),
+                               op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2);
+               }
+               /*
+                * Done with arguments.
+                * Handle readln and
+                * insufficient number of args.
+                */
+               if (p->value[0] == O_READLN) {
+                       if (filetype != nl+T1CHAR)
+                               error("Can't 'readln' a non text file");
+                       put(1, O_READLN);
+               }
+               else if (argc == 0)
+                       error("read requires an argument");
+               return;
+
+       case O_GET:
+       case O_PUT:
+               if (argc != 1) {
+                       error("%s expects one argument", p->symbol);
+                       return;
+               }
+               ap = stkrval(argv[1], NIL , RREQ );
+               if (ap == NIL)
+                       return;
+               if (ap->class != FILET) {
+                       error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
+                       return;
+               }
+               put(1, O_UNIT);
+               put(1, op);
+               return;
+
+       case O_RESET:
+       case O_REWRITE:
+               if (argc == 0 || argc > 2) {
+                       error("%s expects one or two arguments", p->symbol);
+                       return;
+               }
+               if (opt('s') && argc == 2) {
+                       standard();
+                       error("Two argument forms of reset and rewrite are non-standard");
+               }
+               ap = stklval(argv[1], MOD|NOUSE);
+               if (ap == NIL)
+                       return;
+               if (ap->class != FILET) {
+                       error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
+                       return;
+               }
+               if (argc == 2) {
+                       /*
+                        * Optional second argument
+                        * is a string name of a
+                        * UNIX (R) file to be associated.
+                        */
+                       al = argv[2];
+                       al = stkrval(al[1], NOFLAGS , RREQ );
+                       if (al == NIL)
+                               return;
+                       if (classify(al) != TSTR) {
+                               error("Second argument to %s must be a string, not %s", p->symbol, nameof(al));
+                               return;
+                       }
+                       strnglen = width(al);
+               } else {
+                       put(2, O_CON24, NIL);
+                       strnglen = 0;
+               }
+               put(2, O_CON24, strnglen);
+               put(2, O_CON24, text(ap) ? 0: width(ap->type));
+               put(1, op);
+               return;
+
+       case O_NEW:
+       case O_DISPOSE:
+               if (argc == 0) {
+                       error("%s expects at least one argument", p->symbol);
+                       return;
+               }
+               ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD );
+               if (ap == NIL)
+                       return;
+               if (ap->class != PTR) {
+                       error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
+                       return;
+               }
+               ap = ap->type;
+               if (ap == NIL)
+                       return;
+               argv = argv[2];
+               if (argv != NIL) {
+                       if (ap->class != RECORD) {
+                               error("Record required when specifying variant tags");
+                               return;
+                       }
+                       for (; argv != NIL; argv = argv[2]) {
+                               if (ap->ptr[NL_VARNT] == NIL) {
+                                       error("Too many tag fields");
+                                       return;
+                               }
+                               if (!isconst(argv[1])) {
+                                       error("Second and successive arguments to %s must be constants", p->symbol);
+                                       return;
+                               }
+                               gconst(argv[1]);
+                               if (con.ctype == NIL)
+                                       return;
+                               if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) {
+                                       cerror("Specified tag constant type clashed with variant case selector type");
+                                       return;
+                               }
+                               for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
+                                       if (ap->range[0] == con.crval)
+                                               break;
+                               if (ap == NIL) {
+                                       error("No variant case label value equals specified constant value");
+                                       return;
+                               }
+                               ap = ap->ptr[NL_VTOREC];
+                       }
+               }
+               put(2, op, width(ap));
+               return;
+
+       case O_DATE:
+       case O_TIME:
+               if (argc != 1) {
+                       error("%s expects one argument", p->symbol);
+                       return;
+               }
+               ap = stklval(argv[1], MOD|NOUSE);
+               if (ap == NIL)
+                       return;
+               if (classify(ap) != TSTR || width(ap) != 10) {
+                       error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
+                       return;
+               }
+               put(1, op);
+               return;
+
+       case O_HALT:
+               if (argc != 0) {
+                       error("halt takes no arguments");
+                       return;
+               }
+               put(1, op);
+               noreach = 1;
+               return;
+
+       case O_ARGV:
+               if (argc != 2) {
+                       error("argv takes two arguments");
+                       return;
+               }
+               ap = stkrval(argv[1], NIL , RREQ );
+               if (ap == NIL)
+                       return;
+               if (isnta(ap, "i")) {
+                       error("argv's first argument must be an integer, not %s", nameof(ap));
+                       return;
+               }
+               al = argv[2];
+               ap = stklval(al[1], MOD|NOUSE);
+               if (ap == NIL)
+                       return;
+               if (classify(ap) != TSTR) {
+                       error("argv's second argument must be a string, not %s", nameof(ap));
+                       return;
+               }
+               put(2, op, width(ap));
+               return;
+
+       case O_STLIM:
+               if (argc != 1) {
+                       error("stlimit requires one argument");
+                       return;
+               }
+               ap = stkrval(argv[1], NIL , RREQ );
+               if (ap == NIL)
+                       return;
+               if (isnta(ap, "i")) {
+                       error("stlimit's argument must be an integer, not %s", nameof(ap));
+                       return;
+               }
+               if (width(ap) != 4)
+                       put(1, O_STOI);
+               put(1, op);
+               return;
+
+       case O_REMOVE:
+               if (argc != 1) {
+                       error("remove expects one argument");
+                       return;
+               }
+               ap = stkrval(argv[1], NOFLAGS , RREQ );
+               if (ap == NIL)
+                       return;
+               if (classify(ap) != TSTR) {
+                       error("remove's argument must be a string, not %s", nameof(ap));
+                       return;
+               }
+               put(2, O_CON24, width(ap));
+               put(1, op);
+               return;
+
+       case O_LLIMIT:
+               if (argc != 2) {
+                       error("linelimit expects two arguments");
+                       return;
+               }
+               ap = stklval(argv[1], NOFLAGS|NOUSE);
+               if (ap == NIL)
+                       return;
+               if (!text(ap)) {
+                       error("linelimit's first argument must be a text file, not %s", nameof(ap));
+                       return;
+               }
+               al = argv[2];
+               ap = stkrval(al[1], NIL , RREQ );
+               if (ap == NIL)
+                       return;
+               if (isnta(ap, "i")) {
+                       error("linelimit's second argument must be an integer, not %s", nameof(ap));
+                       return;
+               }
+               put(1, op);
+               return;
+       case O_PAGE:
+               if (argc != 1) {
+                       error("page expects one argument");
+                       return;
+               }
+               ap = stkrval(argv[1], NIL , RREQ );
+               if (ap == NIL)
+                       return;
+               if (!text(ap)) {
+                       error("Argument to page must be a text file, not %s", nameof(ap));
+                       return;
+               }
+               put(1, O_UNIT);
+               put(1, op);
+               return;
+
+       case O_PACK:
+               if (argc != 3) {
+                       error("pack expects three arguments");
+                       return;
+               }
+               pu = "pack(a,i,z)";
+               pua = (al = argv)[1];
+               pui = (al = al[2])[1];
+               puz = (al = al[2])[1];
+               goto packunp;
+       case O_UNPACK:
+               if (argc != 3) {
+                       error("unpack expects three arguments");
+                       return;
+               }
+               pu = "unpack(z,a,i)";
+               puz = (al = argv)[1];
+               pua = (al = al[2])[1];
+               pui = (al = al[2])[1];
+packunp:
+               ap = stkrval((int *) pui, NLNIL , RREQ );
+               if (ap == NIL)
+                       return;
+               ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE);
+               if (ap == NIL)
+                       return;
+               if (ap->class != ARRAY) {
+                       error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
+                       return;
+               }
+               al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE);
+               if (al->class != ARRAY) {
+                       error("%s requires z to be a packed array, not %s", pu, nameof(ap));
+                       return;
+               }
+               if (al->type == NIL || ap->type == NIL)
+                       return;
+               if (al->type != ap->type) {
+                       error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
+                       return;
+               }
+               k = width(al);
+               itemwidth = width(ap->type);
+               ap = ap->chain;
+               al = al->chain;
+               if (ap->chain != NIL || al->chain != NIL) {
+                       error("%s requires a and z to be single dimension arrays", pu);
+                       return;
+               }
+               if (ap == NIL || al == NIL)
+                       return;
+               /*
+                * al is the range for z i.e. u..v
+                * ap is the range for a i.e. m..n
+                * i will be n-m+1
+                * j will be v-u+1
+                */
+               i = ap->range[1] - ap->range[0] + 1;
+               j = al->range[1] - al->range[0] + 1;
+               if (i < j) {
+                       error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i);
+                       return;
+               }
+               /*
+                * get n-m-(v-u) and m for the interpreter
+                */
+               i -= j;
+               j = ap->range[0];
+               put(5, op, itemwidth , j, i, k);
+               return;
+       case 0:
+               error("%s is an unimplemented 6400 extension", p->symbol);
+               return;
+
+       default:
+               panic("proc case");
+       }
+}
+#endif OBJ