|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.