Annotation of 42BSD/ucb/pascal/src/proc.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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