Annotation of 3BSD/cmd/pi/proc.c, revision 1.1.1.1

1.1       root        1: /* Copyright (c) 1979 Regents of the University of California */
                      2: #
                      3: /*
                      4:  * pi - Pascal interpreter code translator
                      5:  *
                      6:  * Charles Haley, Bill Joy UCB
                      7:  * Version 1.2 November 1978
                      8:  */
                      9: 
                     10: #include "whoami"
                     11: #include "0.h"
                     12: #include "tree.h"
                     13: #include "opcode.h"
                     14: 
                     15: /*
                     16:  * The following arrays are used to determine which classes may be
                     17:  * read and written to/from text files.
                     18:  * They are indexed by the return types from classify.
                     19:  */
                     20: #define rdops(x) rdxxxx[(x)-(TFIRST)]
                     21: #define wrops(x) wrxxxx[(x)-(TFIRST)]
                     22: 
                     23: int rdxxxx[] = {
                     24:        0,              /* -7  file types */
                     25:        0,              /* -6  record types */
                     26:        0,              /* -5  array types */
                     27:        0,              /* -4  scalar types */
                     28:        0,              /* -3  pointer types */
                     29:        0,              /* -2  set types */
                     30:        0,              /* -1  string types */
                     31:        0,              /*  0  nil - i.e. no type */
                     32:        0,              /*  1  booleans */
                     33:        O_READC,        /*  2  character */
                     34:        O_READ4,        /*  3  integer */
                     35:        O_READ8         /*  4  real */
                     36: };
                     37: 
                     38: int wrxxxx[] = {
                     39:        0,              /* -7  file types */
                     40:        0,              /* -6  record types */
                     41:        0,              /* -5  array types */
                     42:        0,              /* -4  scalar types */
                     43:        0,              /* -3  pointer types */
                     44:        0,              /* -2  set types */
                     45:        O_WRITG,        /* -1  string types */
                     46:        0,              /*  0  nil - i.e. no type */
                     47:        O_WRITB,        /*  1  booleans */
                     48:        O_WRITC,        /*  2  character */
                     49:        O_WRIT4,        /*  3  integer */
                     50:        O_WRIT8,        /*  4  real */
                     51: };
                     52: 
                     53: /*
                     54:  * Proc handles procedure calls.
                     55:  * Non-builtin procedures are "buck-passed" to func (with a flag
                     56:  * indicating that they are actually procedures.
                     57:  * builtin procedures are handled here.
                     58:  */
                     59: proc(r)
                     60:        int *r;
                     61: {
                     62:        register struct nl *p;
                     63:        register int *al, op;
                     64:        struct nl *filetype, *ap;
                     65:        int argc, *argv, c, two, oct, hex, *file;
                     66:        int pu;
                     67:        int *pua, *pui, *puz;
                     68:        int i, j, k;
                     69: 
                     70:        /*
                     71:         * Verify that the name is
                     72:         * defined and is that of a
                     73:         * procedure.
                     74:         */
                     75:        p = lookup(r[2]);
                     76:        if (p == NIL) {
                     77:                rvlist(r[3]);
                     78:                return;
                     79:        }
                     80:        if (p->class != PROC) {
                     81:                error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]);
                     82:                rvlist(r[3]);
                     83:                return;
                     84:        }
                     85:        argv = r[3];
                     86: 
                     87:        /*
                     88:         * Call handles user defined
                     89:         * procedures and functions.
                     90:         */
                     91:        if (bn != 0) {
                     92:                call(p, argv, PROC, bn);
                     93:                return;
                     94:        }
                     95: 
                     96:        /*
                     97:         * Call to built-in procedure.
                     98:         * Count the arguments.
                     99:         */
                    100:        argc = 0;
                    101:        for (al = argv; al != NIL; al = al[2])
                    102:                argc++;
                    103: 
                    104:        /*
                    105:         * Switch on the operator
                    106:         * associated with the built-in
                    107:         * procedure in the namelist
                    108:         */
                    109:        op = p->value[0] &~ NSTAND;
                    110:        if (opt('s') && (p->value[0] & NSTAND)) {
                    111:                standard();
                    112:                error("%s is a nonstandard procedure", p->symbol);
                    113:        }
                    114:        switch (op) {
                    115: 
                    116:        case O_NULL:
                    117:                if (argc != 0)
                    118:                        error("null takes no arguments");
                    119:                return;
                    120: 
                    121:        case O_FLUSH:
                    122:                if (argc == 0) {
                    123:                        put1(O_MESSAGE);
                    124:                        return;
                    125:                }
                    126:                if (argc != 1) {
                    127:                        error("flush takes at most one argument");
                    128:                        return;
                    129:                }
                    130:                ap = rvalue(argv[1], NIL);
                    131:                if (ap == NIL)
                    132:                        return;
                    133:                if (ap->class != FILET) {
                    134:                        error("flush's argument must be a file, not %s", nameof(ap));
                    135:                        return;
                    136:                }
                    137:                put1(op);
                    138:                return;
                    139: 
                    140:        case O_MESSAGE:
                    141:        case O_WRIT2:
                    142:        case O_WRITLN:
                    143:                /*
                    144:                 * Set up default file "output"'s type
                    145:                 */
                    146:                file = NIL;
                    147:                filetype = nl+T1CHAR;
                    148:                /*
                    149:                 * Determine the file implied
                    150:                 * for the write and generate
                    151:                 * code to make it the active file.
                    152:                 */
                    153:                if (op == O_MESSAGE) {
                    154:                        /*
                    155:                         * For message, all that matters
                    156:                         * is that the filetype is
                    157:                         * a character file.
                    158:                         * Thus "output" will suit us fine.
                    159:                         */
                    160:                        put1(O_MESSAGE);
                    161:                } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) {
                    162:                        /*
                    163:                         * If there is a first argument which has
                    164:                         * no write widths, then it is potentially
                    165:                         * a file name.
                    166:                         */
                    167:                        codeoff();
                    168:                        ap = rvalue(argv[1], NIL);
                    169:                        codeon();
                    170:                        if (ap == NIL)
                    171:                                argv = argv[2];
                    172:                        if (ap != NIL && ap->class == FILET) {
                    173:                                /*
                    174:                                 * Got "write(f, ...", make
                    175:                                 * f the active file, and save
                    176:                                 * it and its type for use in
                    177:                                 * processing the rest of the
                    178:                                 * arguments to write.
                    179:                                 */
                    180:                                file = argv[1];
                    181:                                filetype = ap->type;
                    182:                                rvalue(argv[1], NIL);
                    183:                                put1(O_UNIT);
                    184:                                /*
                    185:                                 * Skip over the first argument
                    186:                                 */
                    187:                                argv = argv[2];
                    188:                                argc--;
                    189:                        } else
                    190:                                /*
                    191:                                 * Set up for writing on 
                    192:                                 * standard output.
                    193:                                 */
                    194:                                put1(O_UNITOUT);
                    195:                } else
                    196:                        put1(O_UNITOUT);
                    197:                /*
                    198:                 * Loop and process each
                    199:                 * of the arguments.
                    200:                 */
                    201:                for (; argv != NIL; argv = argv[2]) {
                    202:                        al = argv[1];
                    203:                        if (al == NIL)
                    204:                                continue;
                    205:                        /*
                    206:                         * Op will be used to
                    207:                         * accumulate width information,
                    208:                         * and two records the fact
                    209:                         * that we saw two write widths
                    210:                         */
                    211:                        op = 0;
                    212:                        two = 0;
                    213:                        oct = 0;
                    214:                        hex = 0;
                    215:                        if (al[0] == T_WEXP) {
                    216:                                if (filetype != nl+T1CHAR) {
                    217:                                        error("Write widths allowed only with text files");
                    218:                                        continue;
                    219:                                }
                    220:                                /*
                    221:                                 * Handle width expressions.
                    222:                                 * The basic game here is that width
                    223:                                 * expressions get evaluated and left
                    224:                                 * on the stack and their width's get
                    225:                                 * packed into the high byte of the
                    226:                                 * affected opcode (subop).
                    227:                                 */
                    228:                                if (al[3] == OCT) 
                    229:                                        oct++;
                    230:                                else if (al[3] == HEX)
                    231:                                        hex++;
                    232:                                else if (al[3] != NIL) {
                    233:                                        two++;
                    234:                                        /*
                    235:                                         * Arrange for the write
                    236:                                         * opcode that takes two widths
                    237:                                         */
                    238:                                        op |= O_WRIT82-O_WRIT8;
                    239:                                        ap = rvalue(al[3], NIL);
                    240:                                        if (ap == NIL)
                    241:                                                continue;
                    242:                                        if (isnta(ap, "i")) {
                    243:                                                error("Second write width must be integer, not %s", nameof(ap));
                    244:                                                continue;
                    245:                                        }
                    246:                                        op |= even(width(ap)) << 11;
                    247:                                }
                    248:                                if (al[2] != NIL) {
                    249:                                        ap = rvalue(al[2], NIL);
                    250:                                        if (ap == NIL)
                    251:                                                continue;
                    252:                                        if (isnta(ap, "i")) {
                    253:                                                error("First write width must be integer, not %s", nameof(ap));
                    254:                                                continue;
                    255:                                        }
                    256:                                        op |= even(width(ap)) << 8;
                    257:                                }
                    258:                                al = al[1];
                    259:                                if (al == NIL)
                    260:                                        continue;
                    261:                        }
                    262:                        if (filetype != nl+T1CHAR) {
                    263:                                if (oct || hex) {
                    264:                                        error("Oct/hex allowed only on text files");
                    265:                                        continue;
                    266:                                }
                    267:                                if (op) {
                    268:                                        error("Write widths allowed only on text files");
                    269:                                        continue;
                    270:                                }
                    271:                                /*
                    272:                                 * Generalized write, i.e.
                    273:                                 * to a non-textfile.
                    274:                                 */
                    275:                                rvalue(file, NIL);
                    276:                                put1(O_FNIL);
                    277:                                /*
                    278:                                 * file^ := ...
                    279:                                 */
                    280:                                ap = rvalue(argv[1], NIL);
                    281:                                if (ap == NIL)
                    282:                                        continue;
                    283:                                if (incompat(ap, filetype, argv[1])) {
                    284:                                        cerror("Type mismatch in write to non-text file");
                    285:                                        continue;
                    286:                                }
                    287:                                convert(ap, filetype);
                    288:                                put2(O_AS, width(filetype));
                    289:                                /*
                    290:                                 * put(file)
                    291:                                 */
                    292:                                put1(O_PUT);
                    293:                                continue;
                    294:                        }
                    295:                        /*
                    296:                         * Write to a textfile
                    297:                         *
                    298:                         * Evaluate the expression
                    299:                         * to be written.
                    300:                         */
                    301:                        ap = rvalue(al, NIL);
                    302:                        if (ap == NIL)
                    303:                                continue;
                    304:                        c = classify(ap);
                    305:                        if (two && c != TDOUBLE) {
                    306:                                if (isnta(ap, "i")) {
                    307:                                        error("Only reals can have two write widths");
                    308:                                        continue;
                    309:                                }
                    310:                                convert(ap, nl+TDOUBLE);
                    311:                                c = TDOUBLE;
                    312:                        }
                    313:                        if (oct || hex) {
                    314:                                if (opt('s')) {
                    315:                                        standard();
                    316:                                        error("Oct and hex are non-standard");
                    317:                                }
                    318:                                switch (c) {
                    319:                                        case TREC:
                    320:                                        case TARY:
                    321:                                        case TFILE:
                    322:                                        case TSTR:
                    323:                                        case TSET:
                    324:                                        case TDOUBLE:
                    325:                                                error("Can't write %ss with oct/hex", clnames[c]);
                    326:                                                continue;
                    327:                                }
                    328:                                put1(op | (oct ? O_WROCT2 : O_WRHEX2) | (width(ap) >> 2));
                    329:                                continue;
                    330:                        }
                    331:                        if (wrops(c) == NIL) {
                    332:                                error("Can't write %ss to a text file", clnames[c]);
                    333:                                continue;
                    334:                        }
                    335:                        if (c == TINT && width(ap) != 4)
                    336:                                op |= O_WRIT2;
                    337:                        else
                    338:                                op |= wrops(c);
                    339:                        if (c == TSTR)
                    340:                                put2(op, width(ap));
                    341:                        else
                    342:                                put1(op);
                    343:                }
                    344:                /*
                    345:                 * Done with arguments.
                    346:                 * Handle writeln and
                    347:                 * insufficent number of args.
                    348:                 */
                    349:                switch (p->value[0] &~ NSTAND) {
                    350:                        case O_WRIT2:
                    351:                                if (argc == 0)
                    352:                                        error("Write requires an argument");
                    353:                                break;
                    354:                        case O_MESSAGE:
                    355:                                if (argc == 0)
                    356:                                        error("Message requires an argument");
                    357:                        case O_WRITLN:
                    358:                                if (filetype != nl+T1CHAR)
                    359:                                        error("Can't 'writeln' a non text file");
                    360:                                put1(O_WRITLN);
                    361:                                break;
                    362:                }
                    363:                return;
                    364: 
                    365:        case O_READ4:
                    366:        case O_READLN:
                    367:                /*
                    368:                 * Set up default
                    369:                 * file "input".
                    370:                 */
                    371:                file = NIL;
                    372:                filetype = nl+T1CHAR;
                    373:                /*
                    374:                 * Determine the file implied
                    375:                 * for the read and generate
                    376:                 * code to make it the active file.
                    377:                 */
                    378:                if (argv != NIL) {
                    379:                        codeoff();
                    380:                        ap = rvalue(argv[1], NIL);
                    381:                        codeon();
                    382:                        if (ap == NIL)
                    383:                                argv = argv[2];
                    384:                        if (ap != NIL && ap->class == FILET) {
                    385:                                /*
                    386:                                 * Got "read(f, ...", make
                    387:                                 * f the active file, and save
                    388:                                 * it and its type for use in
                    389:                                 * processing the rest of the
                    390:                                 * arguments to read.
                    391:                                 */
                    392:                                file = argv[1];
                    393:                                filetype = ap->type;
                    394:                                rvalue(argv[1], NIL);
                    395:                                put1(O_UNIT);
                    396:                                argv = argv[2];
                    397:                                argc--;
                    398:                        } else {
                    399:                                /*
                    400:                                 * Default is read from
                    401:                                 * standard input.
                    402:                                 */
                    403:                                put1(O_UNITINP);
                    404:                                input->nl_flags |= NUSED;
                    405:                        }
                    406:                } else {
                    407:                        put1(O_UNITINP);
                    408:                        input->nl_flags |= NUSED;
                    409:                }
                    410:                /*
                    411:                 * Loop and process each
                    412:                 * of the arguments.
                    413:                 */
                    414:                for (; argv != NIL; argv = argv[2]) {
                    415:                        /*
                    416:                         * Get the address of the target
                    417:                         * on the stack.
                    418:                         */
                    419:                        al = argv[1];
                    420:                        if (al == NIL)
                    421:                                continue;
                    422:                        if (al[0] != T_VAR) {
                    423:                                error("Arguments to %s must be variables, not expressions", p->symbol);
                    424:                                continue;
                    425:                        }
                    426:                        ap = lvalue(al, MOD|ASGN|NOUSE);
                    427:                        if (ap == NIL)
                    428:                                continue;
                    429:                        if (filetype != nl+T1CHAR) {
                    430:                                /*
                    431:                                 * Generalized read, i.e.
                    432:                                 * from a non-textfile.
                    433:                                 */
                    434:                                if (incompat(filetype, ap, NIL)) {
                    435:                                        error("Type mismatch in read from non-text file");
                    436:                                        continue;
                    437:                                }
                    438:                                /*
                    439:                                 * var := file ^;
                    440:                                 */
                    441:                                if (file != NIL)
                    442:                                        rvalue(file, NIL);
                    443:                                else /* Magic */
                    444:                                        put2(O_RV2, input->value[0]);
                    445:                                put1(O_FNIL);
                    446:                                put2(O_IND, width(filetype));
                    447:                                convert(filetype, ap);
                    448:                                if (isa(ap, "bsci"))
                    449:                                        rangechk(ap, ap);
                    450:                                put2(O_AS, width(ap));
                    451:                                /*
                    452:                                 * get(file);
                    453:                                 */
                    454:                                put1(O_GET);
                    455:                                continue;
                    456:                        }
                    457:                        c = classify(ap);
                    458:                        op = rdops(c);
                    459:                        if (op == NIL) {
                    460:                                error("Can't read %ss from a text file", clnames[c]);
                    461:                                continue;
                    462:                        }
                    463:                        put1(op);
                    464:                        /*
                    465:                         * Data read is on the stack.
                    466:                         * Assign it.
                    467:                         */
                    468:                        if (op != O_READ8)
                    469:                                rangechk(ap, op == O_READC ? ap : nl+T4INT);
                    470:                        gen(O_AS2, O_AS2, width(ap),
                    471:                                op == O_READ8 ? 8 : op == O_READ4 ? 4 : 2);
                    472:                }
                    473:                /*
                    474:                 * Done with arguments.
                    475:                 * Handle readln and
                    476:                 * insufficient number of args.
                    477:                 */
                    478:                if (p->value[0] == O_READLN) {
                    479:                        if (filetype != nl+T1CHAR)
                    480:                                error("Can't 'readln' a non text file");
                    481:                        put1(O_READLN);
                    482:                }
                    483:                else if (argc == 0)
                    484:                        error("read requires an argument");
                    485:                return;
                    486: 
                    487:        case O_GET:
                    488:        case O_PUT:
                    489:                if (argc != 1) {
                    490:                        error("%s expects one argument", p->symbol);
                    491:                        return;
                    492:                }
                    493:                ap = rvalue(argv[1], NIL);
                    494:                if (ap == NIL)
                    495:                        return;
                    496:                if (ap->class != FILET) {
                    497:                        error("Argument to %s must be a file, not %s", p->symbol, nameof(ap));
                    498:                        return;
                    499:                }
                    500:                put1(O_UNIT);
                    501:                put1(op);
                    502:                return;
                    503: 
                    504:        case O_RESET:
                    505:        case O_REWRITE:
                    506:                if (argc == 0 || argc > 2) {
                    507:                        error("%s expects one or two arguments", p->symbol);
                    508:                        return;
                    509:                }
                    510:                if (opt('s') && argc == 2) {
                    511:                        standard();
                    512:                        error("Two argument forms of reset and rewrite are non-standard");
                    513:                }
                    514:                ap = lvalue(argv[1], MOD|NOUSE);
                    515:                if (ap == NIL)
                    516:                        return;
                    517:                if (ap->class != FILET) {
                    518:                        error("First argument to %s must be a file, not %s", p->symbol, nameof(ap));
                    519:                        return;
                    520:                }
                    521:                if (argc == 2) {
                    522:                        /*
                    523:                         * Optional second argument
                    524:                         * is a string name of a
                    525:                         * UNIX (R) file to be associated.
                    526:                         */
                    527:                        al = argv[2];
                    528:                        al = rvalue(al[1], NIL);
                    529:                        if (al == NIL)
                    530:                                return;
                    531:                        if (classify(al) != TSTR) {
                    532:                                error("Second argument to %s must be a string, not %s", p->symbol, nameof(al));
                    533:                                return;
                    534:                        }
                    535:                        c = width(al);
                    536:                } else
                    537:                        c = 0;
                    538:                if (c > 127) {
                    539:                        error("File name too long");
                    540:                        return;
                    541:                }
                    542:                put2(op | c << 8, text(ap) ? 0: width(ap->type));
                    543:                return;
                    544: 
                    545:        case O_NEW:
                    546:        case O_DISPOSE:
                    547:                if (argc == 0) {
                    548:                        error("%s expects at least one argument", p->symbol);
                    549:                        return;
                    550:                }
                    551:                ap = lvalue(argv[1], MOD|NOUSE);
                    552:                if (ap == NIL)
                    553:                        return;
                    554:                if (ap->class != PTR) {
                    555:                        error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap));
                    556:                        return;
                    557:                }
                    558:                ap = ap->type;
                    559:                if (ap == NIL)
                    560:                        return;
                    561:                argv = argv[2];
                    562:                if (argv != NIL) {
                    563:                        if (ap->class != RECORD) {
                    564:                                error("Record required when specifying variant tags");
                    565:                                return;
                    566:                        }
                    567:                        for (; argv != NIL; argv = argv[2]) {
                    568:                                if (ap->ptr[NL_VARNT] == NIL) {
                    569:                                        error("Too many tag fields");
                    570:                                        return;
                    571:                                }
                    572:                                if (!isconst(argv[1])) {
                    573:                                        error("Second and successive arguments to %s must be constants", p->symbol);
                    574:                                        return;
                    575:                                }
                    576:                                gconst(argv[1]);
                    577:                                if (con.ctype == NIL)
                    578:                                        return;
                    579:                                if (incompat(con.ctype, (ap->ptr[NL_TAG])->type)) {
                    580:                                        cerror("Specified tag constant type clashed with variant case selector type");
                    581:                                        return;
                    582:                                }
                    583:                                for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain)
                    584:                                        if (ap->range[0] == con.crval)
                    585:                                                break;
                    586:                                if (ap == NIL) {
                    587:                                        error("No variant case label value equals specified constant value");
                    588:                                        return;
                    589:                                }
                    590:                                ap = ap->ptr[NL_VTOREC];
                    591:                        }
                    592:                }
                    593:                put2(op, width(ap));
                    594:                return;
                    595: 
                    596:        case O_DATE:
                    597:        case O_TIME:
                    598:                if (argc != 1) {
                    599:                        error("%s expects one argument", p->symbol);
                    600:                        return;
                    601:                }
                    602:                ap = lvalue(argv[1], MOD|NOUSE);
                    603:                if (ap == NIL)
                    604:                        return;
                    605:                if (classify(ap) != TSTR || width(ap) != 10) {
                    606:                        error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap));
                    607:                        return;
                    608:                }
                    609:                put1(op);
                    610:                return;
                    611: 
                    612:        case O_HALT:
                    613:                if (argc != 0) {
                    614:                        error("halt takes no arguments");
                    615:                        return;
                    616:                }
                    617:                put1(op);
                    618:                noreach = 1;
                    619:                return;
                    620: 
                    621:        case O_ARGV:
                    622:                if (argc != 2) {
                    623:                        error("argv takes two arguments");
                    624:                        return;
                    625:                }
                    626:                ap = rvalue(argv[1], NIL);
                    627:                if (ap == NIL)
                    628:                        return;
                    629:                if (isnta(ap, "i")) {
                    630:                        error("argv's first argument must be an integer, not %s", nameof(ap));
                    631:                        return;
                    632:                }
                    633:                convert(ap, nl+T2INT);
                    634:                al = argv[2];
                    635:                ap = lvalue(al[1], MOD|NOUSE);
                    636:                if (ap == NIL)
                    637:                        return;
                    638:                if (classify(ap) != TSTR) {
                    639:                        error("argv's second argument must be a string, not %s", nameof(ap));
                    640:                        return;
                    641:                }
                    642:                put2(op, width(ap));
                    643:                return;
                    644: 
                    645:        case O_STLIM:
                    646:                if (argc != 1) {
                    647:                        error("stlimit requires one argument");
                    648:                        return;
                    649:                }
                    650:                ap = rvalue(argv[1], NIL);
                    651:                if (ap == NIL)
                    652:                        return;
                    653:                if (isnta(ap, "i")) {
                    654:                        error("stlimit's argument must be an integer, not %s", nameof(ap));
                    655:                        return;
                    656:                }
                    657:                if (width(ap) != 4)
                    658:                        put1(O_STOI);
                    659:                put1(op);
                    660:                return;
                    661: 
                    662:        case O_REMOVE:
                    663:                if (argc != 1) {
                    664:                        error("remove expects one argument");
                    665:                        return;
                    666:                }
                    667:                ap = rvalue(argv[1], NIL);
                    668:                if (ap == NIL)
                    669:                        return;
                    670:                if (classify(ap) != TSTR) {
                    671:                        error("remove's argument must be a string, not %s", nameof(ap));
                    672:                        return;
                    673:                }
                    674:                put2(op, width(ap));
                    675:                return;
                    676: 
                    677:        case O_LLIMIT:
                    678:                if (argc != 2) {
                    679:                        error("linelimit expects two arguments");
                    680:                        return;
                    681:                }
                    682:                ap = lvalue(argv[1], NOMOD|NOUSE);
                    683:                if (ap == NIL)
                    684:                        return;
                    685:                if (!text(ap)) {
                    686:                        error("linelimit's first argument must be a text file, not %s", nameof(ap));
                    687:                        return;
                    688:                }
                    689:                al = argv[2];
                    690:                ap = rvalue(al[1], NIL);
                    691:                if (ap == NIL)
                    692:                        return;
                    693:                if (isnta(ap, "i")) {
                    694:                        error("linelimit's second argument must be an integer, not %s", nameof(ap));
                    695:                        return;
                    696:                }
                    697:                convert(ap, nl+T4INT);
                    698:                put1(op);
                    699:                return;
                    700:        case O_PAGE:
                    701:                if (argc != 1) {
                    702:                        error("page expects one argument");
                    703:                        return;
                    704:                }
                    705:                ap = rvalue(argv[1], NIL);
                    706:                if (ap == NIL)
                    707:                        return;
                    708:                if (!text(ap)) {
                    709:                        error("Argument to page must be a text file, not %s", nameof(ap));
                    710:                        return;
                    711:                }
                    712:                put1(O_UNIT);
                    713:                put1(op);
                    714:                return;
                    715: 
                    716:        case O_PACK:
                    717:                if (argc != 3) {
                    718:                        error("pack expects three arguments");
                    719:                        return;
                    720:                }
                    721:                pu = "pack(a,i,z)";
                    722:                pua = (al = argv)[1];
                    723:                pui = (al = al[2])[1];
                    724:                puz = (al = al[2])[1];
                    725:                goto packunp;
                    726:        case O_UNPACK:
                    727:                if (argc != 3) {
                    728:                        error("unpack expects three arguments");
                    729:                        return;
                    730:                }
                    731:                pu = "unpack(z,a,i)";
                    732:                puz = (al = argv)[1];
                    733:                pua = (al = al[2])[1];
                    734:                pui = (al = al[2])[1];
                    735: packunp:
                    736:                ap = rvalue((int *) pui, NLNIL);
                    737:                if (ap == NIL)
                    738:                        return;
                    739:                if (width(ap) == 4)
                    740:                        put1(O_ITOS);
                    741:                ap = lvalue(pua, op == O_PACK ? NOMOD : MOD|NOUSE);
                    742:                if (ap == NIL)
                    743:                        return;
                    744:                if (ap->class != ARRAY) {
                    745:                        error("%s requires a to be an unpacked array, not %s", pu, nameof(ap));
                    746:                        return;
                    747:                }
                    748:                al = (struct nl *) lvalue(puz, op == O_UNPACK ? NOMOD : MOD|NOUSE);
                    749:                if (al->class != ARRAY) {
                    750:                        error("%s requires z to be a packed array, not %s", pu, nameof(ap));
                    751:                        return;
                    752:                }
                    753:                if (al->type == NIL || ap->type == NIL)
                    754:                        return;
                    755:                if (al->type != ap->type) {
                    756:                        error("%s requires a and z to be arrays of the same type", pu, nameof(ap));
                    757:                        return;
                    758:                }
                    759:                k = width(al);
                    760:                ap = ap->chain;
                    761:                al = al->chain;
                    762:                if (ap->chain != NIL || al->chain != NIL) {
                    763:                        error("%s requires a and z to be single dimension arrays", pu);
                    764:                        return;
                    765:                }
                    766:                if (ap == NIL || al == NIL)
                    767:                        return;
                    768:                /*
                    769:                 * al is the range for z i.e. u..v
                    770:                 * ap is the range for a i.e. m..n
                    771:                 * i will be n-m+1
                    772:                 * j will be v-u+1
                    773:                 */
                    774:                i = ap->range[1] - ap->range[0] + 1;
                    775:                j = al->range[1] - al->range[0] + 1;
                    776:                if (i < j) {
                    777:                        error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i);
                    778:                        return;
                    779:                }
                    780:                /*
                    781:                 * get n-m-(v-u) and m for the interpreter
                    782:                 */
                    783:                i -= j;
                    784:                j = ap->range[0];
                    785:                put(5, op, width(ap), j, i, k);
                    786:                return;
                    787:        case 0:
                    788:                error("%s is an unimplemented 6400 extension", p->symbol);
                    789:                return;
                    790: 
                    791:        default:
                    792:                panic("proc case");
                    793:        }
                    794: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.