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