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