1*766Speter /* Copyright (c) 1979 Regents of the University of California */ 2*766Speter 3*766Speter static char sccsid[] = "@(#)pcproc.c 1.1 08/27/80"; 4*766Speter 5*766Speter #include "whoami.h" 6*766Speter #ifdef PC 7*766Speter /* 8*766Speter * and to the end of the file 9*766Speter */ 10*766Speter #include "0.h" 11*766Speter #include "tree.h" 12*766Speter #include "opcode.h" 13*766Speter #include "pc.h" 14*766Speter #include "pcops.h" 15*766Speter 16*766Speter /* 17*766Speter * The following array is used to determine which classes may be read 18*766Speter * from textfiles. It is indexed by the return value from classify. 19*766Speter */ 20*766Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 21*766Speter 22*766Speter int rdxxxx[] = { 23*766Speter 0, /* -7 file types */ 24*766Speter 0, /* -6 record types */ 25*766Speter 0, /* -5 array types */ 26*766Speter O_READE, /* -4 scalar types */ 27*766Speter 0, /* -3 pointer types */ 28*766Speter 0, /* -2 set types */ 29*766Speter 0, /* -1 string types */ 30*766Speter 0, /* 0 nil, no type */ 31*766Speter O_READE, /* 1 boolean */ 32*766Speter O_READC, /* 2 character */ 33*766Speter O_READ4, /* 3 integer */ 34*766Speter O_READ8 /* 4 real */ 35*766Speter }; 36*766Speter 37*766Speter /* 38*766Speter * Proc handles procedure calls. 39*766Speter * Non-builtin procedures are "buck-passed" to func (with a flag 40*766Speter * indicating that they are actually procedures. 41*766Speter * builtin procedures are handled here. 42*766Speter */ 43*766Speter pcproc(r) 44*766Speter int *r; 45*766Speter { 46*766Speter register struct nl *p; 47*766Speter register int *alv, *al, op; 48*766Speter struct nl *filetype, *ap; 49*766Speter int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file; 50*766Speter char fmt, format[20], *strptr; 51*766Speter int prec, field, strnglen, fmtlen, fmtstart, pu; 52*766Speter int *pua, *pui, *puz; 53*766Speter int i, j, k; 54*766Speter int itemwidth; 55*766Speter char *readname; 56*766Speter long tempoff; 57*766Speter long readtype; 58*766Speter 59*766Speter #define CONPREC 4 60*766Speter #define VARPREC 8 61*766Speter #define CONWIDTH 1 62*766Speter #define VARWIDTH 2 63*766Speter #define SKIP 16 64*766Speter 65*766Speter /* 66*766Speter * Verify that the name is 67*766Speter * defined and is that of a 68*766Speter * procedure. 69*766Speter */ 70*766Speter p = lookup(r[2]); 71*766Speter if (p == NIL) { 72*766Speter rvlist(r[3]); 73*766Speter return; 74*766Speter } 75*766Speter if (p->class != PROC) { 76*766Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 77*766Speter rvlist(r[3]); 78*766Speter return; 79*766Speter } 80*766Speter argv = r[3]; 81*766Speter 82*766Speter /* 83*766Speter * Call handles user defined 84*766Speter * procedures and functions. 85*766Speter */ 86*766Speter if (bn != 0) { 87*766Speter call(p, argv, PROC, bn); 88*766Speter return; 89*766Speter } 90*766Speter 91*766Speter /* 92*766Speter * Call to built-in procedure. 93*766Speter * Count the arguments. 94*766Speter */ 95*766Speter argc = 0; 96*766Speter for (al = argv; al != NIL; al = al[2]) 97*766Speter argc++; 98*766Speter 99*766Speter /* 100*766Speter * Switch on the operator 101*766Speter * associated with the built-in 102*766Speter * procedure in the namelist 103*766Speter */ 104*766Speter op = p->value[0] &~ NSTAND; 105*766Speter if (opt('s') && (p->value[0] & NSTAND)) { 106*766Speter standard(); 107*766Speter error("%s is a nonstandard procedure", p->symbol); 108*766Speter } 109*766Speter switch (op) { 110*766Speter 111*766Speter case O_ABORT: 112*766Speter if (argc != 0) 113*766Speter error("null takes no arguments"); 114*766Speter return; 115*766Speter 116*766Speter case O_FLUSH: 117*766Speter if (argc == 0) { 118*766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 119*766Speter putop( P2UNARY P2CALL , P2INT ); 120*766Speter putdot( filename , line ); 121*766Speter return; 122*766Speter } 123*766Speter if (argc != 1) { 124*766Speter error("flush takes at most one argument"); 125*766Speter return; 126*766Speter } 127*766Speter putleaf( P2ICON , 0 , 0 128*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 129*766Speter , "_FLUSH" ); 130*766Speter ap = stklval(argv[1], NOFLAGS); 131*766Speter if (ap == NIL) 132*766Speter return; 133*766Speter if (ap->class != FILET) { 134*766Speter error("flush's argument must be a file, not %s", nameof(ap)); 135*766Speter return; 136*766Speter } 137*766Speter putop( P2CALL , P2INT ); 138*766Speter putdot( filename , line ); 139*766Speter return; 140*766Speter 141*766Speter case O_MESSAGE: 142*766Speter case O_WRITEF: 143*766Speter case O_WRITLN: 144*766Speter /* 145*766Speter * Set up default file "output"'s type 146*766Speter */ 147*766Speter file = NIL; 148*766Speter filetype = nl+T1CHAR; 149*766Speter /* 150*766Speter * Determine the file implied 151*766Speter * for the write and generate 152*766Speter * code to make it the active file. 153*766Speter */ 154*766Speter if (op == O_MESSAGE) { 155*766Speter /* 156*766Speter * For message, all that matters 157*766Speter * is that the filetype is 158*766Speter * a character file. 159*766Speter * Thus "output" will suit us fine. 160*766Speter */ 161*766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 162*766Speter putop( P2UNARY P2CALL , P2INT ); 163*766Speter putdot( filename , line ); 164*766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 165*766Speter putLV( "__err" , 0 , 0 , P2PTR|P2STRTY ); 166*766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 167*766Speter putdot( filename , line ); 168*766Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 169*766Speter /* 170*766Speter * If there is a first argument which has 171*766Speter * no write widths, then it is potentially 172*766Speter * a file name. 173*766Speter */ 174*766Speter codeoff(); 175*766Speter ap = stkrval(argv[1], NIL , RREQ ); 176*766Speter codeon(); 177*766Speter if (ap == NIL) 178*766Speter argv = argv[2]; 179*766Speter if (ap != NIL && ap->class == FILET) { 180*766Speter /* 181*766Speter * Got "write(f, ...", make 182*766Speter * f the active file, and save 183*766Speter * it and its type for use in 184*766Speter * processing the rest of the 185*766Speter * arguments to write. 186*766Speter */ 187*766Speter putRV( 0 , cbn , CURFILEOFFSET 188*766Speter , P2PTR|P2STRTY ); 189*766Speter putleaf( P2ICON , 0 , 0 190*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 191*766Speter , "_UNIT" ); 192*766Speter file = argv[1]; 193*766Speter filetype = ap->type; 194*766Speter stklval(argv[1], NOFLAGS); 195*766Speter putop( P2CALL , P2INT ); 196*766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 197*766Speter putdot( filename , line ); 198*766Speter /* 199*766Speter * Skip over the first argument 200*766Speter */ 201*766Speter argv = argv[2]; 202*766Speter argc--; 203*766Speter } else { 204*766Speter /* 205*766Speter * Set up for writing on 206*766Speter * standard output. 207*766Speter */ 208*766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 209*766Speter putLV( "_output" , 0 , 0 , P2PTR|P2STRTY ); 210*766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 211*766Speter putdot( filename , line ); 212*766Speter } 213*766Speter } else { 214*766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 215*766Speter putLV( "_output" , 0 , 0 , P2PTR|P2STRTY ); 216*766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 217*766Speter putdot( filename , line ); 218*766Speter } 219*766Speter /* 220*766Speter * Loop and process each 221*766Speter * of the arguments. 222*766Speter */ 223*766Speter for (; argv != NIL; argv = argv[2]) { 224*766Speter /* 225*766Speter * fmtspec indicates the type (CONstant or VARiable) 226*766Speter * and number (none, WIDTH, and/or PRECision) 227*766Speter * of the fields in the printf format for this 228*766Speter * output variable. 229*766Speter * stkcnt is the number of longs pushed on the stack 230*766Speter * fmt is the format output indicator (D, E, F, O, X, S) 231*766Speter * fmtstart = 0 for leading blank; = 1 for no blank 232*766Speter */ 233*766Speter fmtspec = NIL; 234*766Speter stkcnt = 0; 235*766Speter fmt = 'D'; 236*766Speter fmtstart = 1; 237*766Speter al = argv[1]; 238*766Speter if (al == NIL) 239*766Speter continue; 240*766Speter if (al[0] == T_WEXP) 241*766Speter alv = al[1]; 242*766Speter else 243*766Speter alv = al; 244*766Speter if (alv == NIL) 245*766Speter continue; 246*766Speter codeoff(); 247*766Speter ap = stkrval(alv, NIL , RREQ ); 248*766Speter codeon(); 249*766Speter if (ap == NIL) 250*766Speter continue; 251*766Speter typ = classify(ap); 252*766Speter if (al[0] == T_WEXP) { 253*766Speter /* 254*766Speter * Handle width expressions. 255*766Speter * The basic game here is that width 256*766Speter * expressions get evaluated. If they 257*766Speter * are constant, the value is placed 258*766Speter * directly in the format string. 259*766Speter * Otherwise the value is pushed onto 260*766Speter * the stack and an indirection is 261*766Speter * put into the format string. 262*766Speter */ 263*766Speter if (al[3] == OCT) 264*766Speter fmt = 'O'; 265*766Speter else if (al[3] == HEX) 266*766Speter fmt = 'X'; 267*766Speter else if (al[3] != NIL) { 268*766Speter /* 269*766Speter * Evaluate second format spec 270*766Speter */ 271*766Speter if ( constval(al[3]) 272*766Speter && isa( con.ctype , "i" ) ) { 273*766Speter fmtspec += CONPREC; 274*766Speter prec = con.crval; 275*766Speter } else { 276*766Speter fmtspec += VARPREC; 277*766Speter } 278*766Speter fmt = 'f'; 279*766Speter switch ( typ ) { 280*766Speter case TINT: 281*766Speter if ( opt( 's' ) ) { 282*766Speter standard(); 283*766Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 284*766Speter } 285*766Speter /* and fall through */ 286*766Speter case TDOUBLE: 287*766Speter break; 288*766Speter default: 289*766Speter error("Cannot write %ss with two write widths", clnames[typ]); 290*766Speter continue; 291*766Speter } 292*766Speter } 293*766Speter /* 294*766Speter * Evaluate first format spec 295*766Speter */ 296*766Speter if (al[2] != NIL) { 297*766Speter if ( constval(al[2]) 298*766Speter && isa( con.ctype , "i" ) ) { 299*766Speter fmtspec += CONWIDTH; 300*766Speter field = con.crval; 301*766Speter } else { 302*766Speter fmtspec += VARWIDTH; 303*766Speter } 304*766Speter } 305*766Speter if ((fmtspec & CONPREC) && prec < 0 || 306*766Speter (fmtspec & CONWIDTH) && field < 0) { 307*766Speter error("Negative widths are not allowed"); 308*766Speter continue; 309*766Speter } 310*766Speter } 311*766Speter if (filetype != nl+T1CHAR) { 312*766Speter if (fmt == 'O' || fmt == 'X') { 313*766Speter error("Oct/hex allowed only on text files"); 314*766Speter continue; 315*766Speter } 316*766Speter if (fmtspec) { 317*766Speter error("Write widths allowed only on text files"); 318*766Speter continue; 319*766Speter } 320*766Speter /* 321*766Speter * Generalized write, i.e. 322*766Speter * to a non-textfile. 323*766Speter */ 324*766Speter putleaf( P2ICON , 0 , 0 325*766Speter , ADDTYPE( 326*766Speter ADDTYPE( 327*766Speter ADDTYPE( p2type( filetype ) 328*766Speter , P2PTR ) 329*766Speter , P2FTN ) 330*766Speter , P2PTR ) 331*766Speter , "_FNIL" ); 332*766Speter stklval(file, NOFLAGS); 333*766Speter putop( P2CALL 334*766Speter , ADDTYPE( p2type( filetype ) , P2PTR ) ); 335*766Speter putop( P2UNARY P2MUL , p2type( filetype ) ); 336*766Speter /* 337*766Speter * file^ := ... 338*766Speter */ 339*766Speter switch ( classify( filetype ) ) { 340*766Speter case TBOOL: 341*766Speter case TCHAR: 342*766Speter case TINT: 343*766Speter case TSCAL: 344*766Speter precheck( filetype , "_RANG4" , "_RSGN4" ); 345*766Speter /* and fall through */ 346*766Speter case TDOUBLE: 347*766Speter case TPTR: 348*766Speter ap = rvalue( argv[1] , filetype , RREQ ); 349*766Speter break; 350*766Speter default: 351*766Speter ap = rvalue( argv[1] , filetype , LREQ ); 352*766Speter break; 353*766Speter } 354*766Speter if (ap == NIL) 355*766Speter continue; 356*766Speter if (incompat(ap, filetype, argv[1])) { 357*766Speter cerror("Type mismatch in write to non-text file"); 358*766Speter continue; 359*766Speter } 360*766Speter switch ( classify( filetype ) ) { 361*766Speter case TBOOL: 362*766Speter case TCHAR: 363*766Speter case TINT: 364*766Speter case TSCAL: 365*766Speter postcheck( filetype ); 366*766Speter /* and fall through */ 367*766Speter case TDOUBLE: 368*766Speter case TPTR: 369*766Speter putop( P2ASSIGN , p2type( filetype ) ); 370*766Speter putdot( filename , line ); 371*766Speter break; 372*766Speter default: 373*766Speter putstrop( P2STASG 374*766Speter , p2type( filetype ) 375*766Speter , lwidth( filetype ) 376*766Speter , align( filetype ) ); 377*766Speter putdot( filename , line ); 378*766Speter break; 379*766Speter } 380*766Speter /* 381*766Speter * put(file) 382*766Speter */ 383*766Speter putleaf( P2ICON , 0 , 0 384*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 385*766Speter , "_PUT" ); 386*766Speter putRV( 0 , cbn , CURFILEOFFSET 387*766Speter , P2PTR|P2STRTY ); 388*766Speter putop( P2CALL , P2INT ); 389*766Speter putdot( filename , line ); 390*766Speter continue; 391*766Speter } 392*766Speter /* 393*766Speter * Write to a textfile 394*766Speter * 395*766Speter * Evaluate the expression 396*766Speter * to be written. 397*766Speter */ 398*766Speter if (fmt == 'O' || fmt == 'X') { 399*766Speter if (opt('s')) { 400*766Speter standard(); 401*766Speter error("Oct and hex are non-standard"); 402*766Speter } 403*766Speter if (typ == TSTR || typ == TDOUBLE) { 404*766Speter error("Can't write %ss with oct/hex", clnames[typ]); 405*766Speter continue; 406*766Speter } 407*766Speter if (typ == TCHAR || typ == TBOOL) 408*766Speter typ = TINT; 409*766Speter } 410*766Speter /* 411*766Speter * If there is no format specified by the programmer, 412*766Speter * implement the default. 413*766Speter */ 414*766Speter switch (typ) { 415*766Speter case TINT: 416*766Speter if (fmt == 'f') { 417*766Speter typ = TDOUBLE; 418*766Speter goto tdouble; 419*766Speter } 420*766Speter if (fmtspec == NIL) { 421*766Speter if (fmt == 'D') 422*766Speter field = 10; 423*766Speter else if (fmt == 'X') 424*766Speter field = 8; 425*766Speter else if (fmt == 'O') 426*766Speter field = 11; 427*766Speter else 428*766Speter panic("fmt1"); 429*766Speter fmtspec = CONWIDTH; 430*766Speter } 431*766Speter break; 432*766Speter case TCHAR: 433*766Speter tchar: 434*766Speter fmt = 'c'; 435*766Speter break; 436*766Speter case TSCAL: 437*766Speter if (opt('s')) { 438*766Speter standard(); 439*766Speter error("Writing scalars to text files is non-standard"); 440*766Speter } 441*766Speter case TBOOL: 442*766Speter fmt = 's'; 443*766Speter break; 444*766Speter case TDOUBLE: 445*766Speter tdouble: 446*766Speter switch (fmtspec) { 447*766Speter case NIL: 448*766Speter field = 21; 449*766Speter prec = 14; 450*766Speter fmt = 'E'; 451*766Speter fmtspec = CONWIDTH + CONPREC; 452*766Speter break; 453*766Speter case CONWIDTH: 454*766Speter if (--field < 1) 455*766Speter field = 1; 456*766Speter prec = field - 7; 457*766Speter if (prec < 1) 458*766Speter prec = 1; 459*766Speter fmtspec += CONPREC; 460*766Speter fmt = 'E'; 461*766Speter break; 462*766Speter case VARWIDTH: 463*766Speter fmtspec += VARPREC; 464*766Speter fmt = 'E'; 465*766Speter break; 466*766Speter case CONWIDTH + CONPREC: 467*766Speter case CONWIDTH + VARPREC: 468*766Speter if (--field < 1) 469*766Speter field = 1; 470*766Speter } 471*766Speter format[0] = ' '; 472*766Speter fmtstart = 0; 473*766Speter break; 474*766Speter case TSTR: 475*766Speter constval( alv ); 476*766Speter switch ( classify( con.ctype ) ) { 477*766Speter case TCHAR: 478*766Speter typ = TCHAR; 479*766Speter goto tchar; 480*766Speter case TSTR: 481*766Speter strptr = con.cpval; 482*766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 483*766Speter strptr = con.cpval; 484*766Speter break; 485*766Speter default: 486*766Speter strnglen = width(ap); 487*766Speter break; 488*766Speter } 489*766Speter fmt = 's'; 490*766Speter strfmt = fmtspec; 491*766Speter if (fmtspec == NIL) { 492*766Speter fmtspec = SKIP; 493*766Speter break; 494*766Speter } 495*766Speter if (fmtspec & CONWIDTH) { 496*766Speter if (field <= strnglen) 497*766Speter fmtspec = SKIP; 498*766Speter else 499*766Speter field -= strnglen; 500*766Speter } 501*766Speter break; 502*766Speter default: 503*766Speter error("Can't write %ss to a text file", clnames[typ]); 504*766Speter continue; 505*766Speter } 506*766Speter /* 507*766Speter * Generate the format string 508*766Speter */ 509*766Speter switch (fmtspec) { 510*766Speter default: 511*766Speter panic("fmt2"); 512*766Speter case NIL: 513*766Speter if (fmt == 'c') { 514*766Speter if ( opt( 't' ) ) { 515*766Speter putleaf( P2ICON , 0 , 0 516*766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 517*766Speter , "_WRITEC" ); 518*766Speter putRV( 0 , cbn , CURFILEOFFSET 519*766Speter , P2PTR|P2STRTY ); 520*766Speter stkrval( alv , NIL , RREQ ); 521*766Speter putop( P2LISTOP , P2INT ); 522*766Speter } else { 523*766Speter putleaf( P2ICON , 0 , 0 524*766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 525*766Speter , "_fputc" ); 526*766Speter stkrval( alv , NIL , RREQ ); 527*766Speter } 528*766Speter putleaf( P2ICON , 0 , 0 529*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 530*766Speter , "_ACTFILE" ); 531*766Speter putRV( 0, cbn , CURFILEOFFSET 532*766Speter , P2PTR|P2STRTY ); 533*766Speter putop( P2CALL , P2INT ); 534*766Speter putop( P2LISTOP , P2INT ); 535*766Speter putop( P2CALL , P2INT ); 536*766Speter putdot( filename , line ); 537*766Speter } else { 538*766Speter sprintf(&format[1], "%%%c", fmt); 539*766Speter goto fmtgen; 540*766Speter } 541*766Speter case SKIP: 542*766Speter break; 543*766Speter case CONWIDTH: 544*766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 545*766Speter goto fmtgen; 546*766Speter case VARWIDTH: 547*766Speter sprintf(&format[1], "%%*%c", fmt); 548*766Speter goto fmtgen; 549*766Speter case CONWIDTH + CONPREC: 550*766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 551*766Speter goto fmtgen; 552*766Speter case CONWIDTH + VARPREC: 553*766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 554*766Speter goto fmtgen; 555*766Speter case VARWIDTH + CONPREC: 556*766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 557*766Speter goto fmtgen; 558*766Speter case VARWIDTH + VARPREC: 559*766Speter sprintf(&format[1], "%%*.*%c", fmt); 560*766Speter fmtgen: 561*766Speter if ( opt( 't' ) ) { 562*766Speter putleaf( P2ICON , 0 , 0 563*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 564*766Speter , "_WRITEF" ); 565*766Speter putRV( 0 , cbn , CURFILEOFFSET 566*766Speter , P2PTR|P2STRTY ); 567*766Speter putleaf( P2ICON , 0 , 0 568*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 569*766Speter , "_ACTFILE" ); 570*766Speter putRV( 0 , cbn , CURFILEOFFSET 571*766Speter , P2PTR|P2STRTY ); 572*766Speter putop( P2CALL , P2INT ); 573*766Speter putop( P2LISTOP , P2INT ); 574*766Speter } else { 575*766Speter putleaf( P2ICON , 0 , 0 576*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 577*766Speter , "_fprintf" ); 578*766Speter putleaf( P2ICON , 0 , 0 579*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 580*766Speter , "_ACTFILE" ); 581*766Speter putRV( 0 , cbn , CURFILEOFFSET 582*766Speter , P2PTR|P2STRTY ); 583*766Speter putop( P2CALL , P2INT ); 584*766Speter } 585*766Speter putCONG( &format[ fmtstart ] 586*766Speter , strlen( &format[ fmtstart ] ) 587*766Speter , LREQ ); 588*766Speter putop( P2LISTOP , P2INT ); 589*766Speter if ( fmtspec & VARWIDTH ) { 590*766Speter /* 591*766Speter * either 592*766Speter * ,(temp=width,MAX(temp,...)), 593*766Speter * or 594*766Speter * , MAX( width , ... ) , 595*766Speter */ 596*766Speter if ( ( typ == TDOUBLE && al[3] == NIL ) 597*766Speter || typ == TSTR ) { 598*766Speter sizes[ cbn ].om_off -= sizeof( int ); 599*766Speter tempoff = sizes[ cbn ].om_off; 600*766Speter putlbracket( ftnno , -tempoff ); 601*766Speter if ( tempoff < sizes[ cbn ].om_max ) { 602*766Speter sizes[ cbn ].om_max = tempoff; 603*766Speter } 604*766Speter putRV( 0 , cbn , tempoff , P2INT ); 605*766Speter ap = stkrval( al[2] , NIL , RREQ ); 606*766Speter putop( P2ASSIGN , P2INT ); 607*766Speter putleaf( P2ICON , 0 , 0 608*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 609*766Speter , "_MAX" ); 610*766Speter putRV( 0 , cbn , tempoff , P2INT ); 611*766Speter } else { 612*766Speter if (opt('t') 613*766Speter || typ == TSTR || typ == TDOUBLE) { 614*766Speter putleaf( P2ICON , 0 , 0 615*766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 616*766Speter ,"_MAX" ); 617*766Speter } 618*766Speter ap = stkrval( al[2] , NIL , RREQ ); 619*766Speter } 620*766Speter if (ap == NIL) 621*766Speter continue; 622*766Speter if (isnta(ap,"i")) { 623*766Speter error("First write width must be integer, not %s", nameof(ap)); 624*766Speter continue; 625*766Speter } 626*766Speter switch ( typ ) { 627*766Speter case TDOUBLE: 628*766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 629*766Speter putop( P2LISTOP , P2INT ); 630*766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 631*766Speter putop( P2LISTOP , P2INT ); 632*766Speter putop( P2CALL , P2INT ); 633*766Speter if ( al[3] == NIL ) { 634*766Speter /* 635*766Speter * finish up the comma op 636*766Speter */ 637*766Speter putop( P2COMOP , P2INT ); 638*766Speter fmtspec &= ~VARPREC; 639*766Speter putop( P2LISTOP , P2INT ); 640*766Speter putleaf( P2ICON , 0 , 0 641*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 642*766Speter , "_MAX" ); 643*766Speter putRV( 0 , cbn , tempoff , P2INT ); 644*766Speter sizes[ cbn ].om_off += sizeof( int ); 645*766Speter putleaf( P2ICON , 8 , 0 , P2INT , 0 ); 646*766Speter putop( P2LISTOP , P2INT ); 647*766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 648*766Speter putop( P2LISTOP , P2INT ); 649*766Speter putop( P2CALL , P2INT ); 650*766Speter } 651*766Speter putop( P2LISTOP , P2INT ); 652*766Speter break; 653*766Speter case TSTR: 654*766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 655*766Speter putop( P2LISTOP , P2INT ); 656*766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 657*766Speter putop( P2LISTOP , P2INT ); 658*766Speter putop( P2CALL , P2INT ); 659*766Speter putop( P2COMOP , P2INT ); 660*766Speter putop( P2LISTOP , P2INT ); 661*766Speter break; 662*766Speter default: 663*766Speter if (opt('t')) { 664*766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 665*766Speter putop( P2LISTOP , P2INT ); 666*766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 667*766Speter putop( P2LISTOP , P2INT ); 668*766Speter putop( P2CALL , P2INT ); 669*766Speter } 670*766Speter putop( P2LISTOP , P2INT ); 671*766Speter break; 672*766Speter } 673*766Speter } 674*766Speter /* 675*766Speter * If there is a variable precision, 676*766Speter * evaluate it 677*766Speter */ 678*766Speter if (fmtspec & VARPREC) { 679*766Speter if (opt('t')) { 680*766Speter putleaf( P2ICON , 0 , 0 681*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 682*766Speter , "_MAX" ); 683*766Speter } 684*766Speter ap = stkrval( al[3] , NIL , RREQ ); 685*766Speter if (ap == NIL) 686*766Speter continue; 687*766Speter if (isnta(ap,"i")) { 688*766Speter error("Second write width must be integer, not %s", nameof(ap)); 689*766Speter continue; 690*766Speter } 691*766Speter if (opt('t')) { 692*766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 693*766Speter putop( P2LISTOP , P2INT ); 694*766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 695*766Speter putop( P2LISTOP , P2INT ); 696*766Speter putop( P2CALL , P2INT ); 697*766Speter } 698*766Speter putop( P2LISTOP , P2INT ); 699*766Speter } 700*766Speter /* 701*766Speter * evaluate the thing we want printed. 702*766Speter */ 703*766Speter switch ( typ ) { 704*766Speter case TCHAR: 705*766Speter case TINT: 706*766Speter stkrval( alv , NIL , RREQ ); 707*766Speter putop( P2LISTOP , P2INT ); 708*766Speter break; 709*766Speter case TDOUBLE: 710*766Speter ap = stkrval( alv , NIL , RREQ ); 711*766Speter if ( isnta( ap , "d" ) ) { 712*766Speter putop( P2SCONV , P2DOUBLE ); 713*766Speter } 714*766Speter putop( P2LISTOP , P2INT ); 715*766Speter break; 716*766Speter case TSCAL: 717*766Speter case TBOOL: 718*766Speter putleaf( P2ICON , 0 , 0 719*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 720*766Speter , "_NAM" ); 721*766Speter ap = stkrval( alv , NIL , RREQ ); 722*766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 723*766Speter , listnames( ap ) ); 724*766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 725*766Speter , format ); 726*766Speter putop( P2LISTOP , P2INT ); 727*766Speter putop( P2CALL , P2INT ); 728*766Speter putop( P2LISTOP , P2INT ); 729*766Speter break; 730*766Speter case TSTR: 731*766Speter putCONG( "" , 0 , LREQ ); 732*766Speter putop( P2LISTOP , P2INT ); 733*766Speter break; 734*766Speter } 735*766Speter putop( P2CALL , P2INT ); 736*766Speter putdot( filename , line ); 737*766Speter } 738*766Speter /* 739*766Speter * Write the string after its blank padding 740*766Speter */ 741*766Speter if (typ == TSTR ) { 742*766Speter if ( opt( 't' ) ) { 743*766Speter putleaf( P2ICON , 0 , 0 744*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 745*766Speter , "_WRITES" ); 746*766Speter putRV( 0 , cbn , CURFILEOFFSET 747*766Speter , P2PTR|P2STRTY ); 748*766Speter ap = stkrval(alv, NIL , RREQ ); 749*766Speter putop( P2LISTOP , P2INT ); 750*766Speter } else { 751*766Speter putleaf( P2ICON , 0 , 0 752*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 753*766Speter , "_fwrite" ); 754*766Speter ap = stkrval(alv, NIL , RREQ ); 755*766Speter } 756*766Speter if (strfmt & VARWIDTH) { 757*766Speter /* 758*766Speter * min, inline expanded as 759*766Speter * temp < len ? temp : len 760*766Speter */ 761*766Speter putRV( 0 , cbn , tempoff , P2INT ); 762*766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 763*766Speter putop( P2LT , P2INT ); 764*766Speter putRV( 0 , cbn , tempoff , P2INT ); 765*766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 766*766Speter putop( P2COLON , P2INT ); 767*766Speter putop( P2QUEST , P2INT ); 768*766Speter } else { 769*766Speter if ( ( fmtspec & SKIP ) 770*766Speter && ( strfmt & CONWIDTH ) ) { 771*766Speter strnglen = field; 772*766Speter } 773*766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 774*766Speter } 775*766Speter putop( P2LISTOP , P2INT ); 776*766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 777*766Speter putop( P2LISTOP , P2INT ); 778*766Speter putleaf( P2ICON , 0 , 0 779*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 780*766Speter , "_ACTFILE" ); 781*766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 782*766Speter putop( P2CALL , P2INT ); 783*766Speter putop( P2LISTOP , P2INT ); 784*766Speter putop( P2CALL , P2INT ); 785*766Speter putdot( filename , line ); 786*766Speter } 787*766Speter } 788*766Speter /* 789*766Speter * Done with arguments. 790*766Speter * Handle writeln and 791*766Speter * insufficent number of args. 792*766Speter */ 793*766Speter switch (p->value[0] &~ NSTAND) { 794*766Speter case O_WRITEF: 795*766Speter if (argc == 0) 796*766Speter error("Write requires an argument"); 797*766Speter break; 798*766Speter case O_MESSAGE: 799*766Speter if (argc == 0) 800*766Speter error("Message requires an argument"); 801*766Speter case O_WRITLN: 802*766Speter if (filetype != nl+T1CHAR) 803*766Speter error("Can't 'writeln' a non text file"); 804*766Speter if ( opt( 't' ) ) { 805*766Speter putleaf( P2ICON , 0 , 0 806*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 807*766Speter , "_WRITLN" ); 808*766Speter putRV( 0 , cbn , CURFILEOFFSET 809*766Speter , P2PTR|P2STRTY ); 810*766Speter } else { 811*766Speter putleaf( P2ICON , 0 , 0 812*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 813*766Speter , "_fputc" ); 814*766Speter putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 ); 815*766Speter putleaf( P2ICON , 0 , 0 816*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 817*766Speter , "_ACTFILE" ); 818*766Speter putRV( 0 , cbn , CURFILEOFFSET 819*766Speter , P2PTR|P2STRTY ); 820*766Speter putop( P2CALL , P2INT ); 821*766Speter putop( P2LISTOP , P2INT ); 822*766Speter } 823*766Speter putop( P2CALL , P2INT ); 824*766Speter putdot( filename , line ); 825*766Speter break; 826*766Speter } 827*766Speter return; 828*766Speter 829*766Speter case O_READ4: 830*766Speter case O_READLN: 831*766Speter /* 832*766Speter * Set up default 833*766Speter * file "input". 834*766Speter */ 835*766Speter file = NIL; 836*766Speter filetype = nl+T1CHAR; 837*766Speter /* 838*766Speter * Determine the file implied 839*766Speter * for the read and generate 840*766Speter * code to make it the active file. 841*766Speter */ 842*766Speter if (argv != NIL) { 843*766Speter codeoff(); 844*766Speter ap = stkrval(argv[1], NIL , RREQ ); 845*766Speter codeon(); 846*766Speter if (ap == NIL) 847*766Speter argv = argv[2]; 848*766Speter if (ap != NIL && ap->class == FILET) { 849*766Speter /* 850*766Speter * Got "read(f, ...", make 851*766Speter * f the active file, and save 852*766Speter * it and its type for use in 853*766Speter * processing the rest of the 854*766Speter * arguments to read. 855*766Speter */ 856*766Speter file = argv[1]; 857*766Speter filetype = ap->type; 858*766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 859*766Speter putleaf( P2ICON , 0 , 0 860*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 861*766Speter , "_UNIT" ); 862*766Speter stklval(argv[1], NOFLAGS); 863*766Speter putop( P2CALL , P2INT ); 864*766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 865*766Speter putdot( filename , line ); 866*766Speter argv = argv[2]; 867*766Speter argc--; 868*766Speter } else { 869*766Speter /* 870*766Speter * Default is read from 871*766Speter * standard input. 872*766Speter */ 873*766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 874*766Speter putLV( "_input" , 0 , 0 , P2PTR|P2STRTY ); 875*766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 876*766Speter putdot( filename , line ); 877*766Speter input->nl_flags |= NUSED; 878*766Speter } 879*766Speter } else { 880*766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 881*766Speter putLV( "_input" , 0 , 0 , P2PTR|P2STRTY ); 882*766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 883*766Speter putdot( filename , line ); 884*766Speter input->nl_flags |= NUSED; 885*766Speter } 886*766Speter /* 887*766Speter * Loop and process each 888*766Speter * of the arguments. 889*766Speter */ 890*766Speter for (; argv != NIL; argv = argv[2]) { 891*766Speter /* 892*766Speter * Get the address of the target 893*766Speter * on the stack. 894*766Speter */ 895*766Speter al = argv[1]; 896*766Speter if (al == NIL) 897*766Speter continue; 898*766Speter if (al[0] != T_VAR) { 899*766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 900*766Speter continue; 901*766Speter } 902*766Speter codeoff(); 903*766Speter ap = stklval(al, MOD|ASGN|NOUSE); 904*766Speter codeon(); 905*766Speter if (ap == NIL) 906*766Speter continue; 907*766Speter if (filetype != nl+T1CHAR) { 908*766Speter /* 909*766Speter * Generalized read, i.e. 910*766Speter * from a non-textfile. 911*766Speter */ 912*766Speter if (incompat(filetype, ap, argv[1] )) { 913*766Speter error("Type mismatch in read from non-text file"); 914*766Speter continue; 915*766Speter } 916*766Speter /* 917*766Speter * var := file ^; 918*766Speter */ 919*766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 920*766Speter if ( isa( ap , "bsci" ) ) { 921*766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 922*766Speter } 923*766Speter putleaf( P2ICON , 0 , 0 924*766Speter , ADDTYPE( 925*766Speter ADDTYPE( 926*766Speter ADDTYPE( 927*766Speter p2type( filetype ) , P2PTR ) 928*766Speter , P2FTN ) 929*766Speter , P2PTR ) 930*766Speter , "_FNIL" ); 931*766Speter if (file != NIL) 932*766Speter stklval(file, NOFLAGS); 933*766Speter else /* Magic */ 934*766Speter putRV( "_input" , 0 , 0 935*766Speter , P2PTR | P2STRTY ); 936*766Speter putop( P2CALL , P2INT ); 937*766Speter switch ( classify( filetype ) ) { 938*766Speter case TBOOL: 939*766Speter case TCHAR: 940*766Speter case TINT: 941*766Speter case TSCAL: 942*766Speter case TDOUBLE: 943*766Speter case TPTR: 944*766Speter putop( P2UNARY P2MUL 945*766Speter , p2type( filetype ) ); 946*766Speter } 947*766Speter switch ( classify( filetype ) ) { 948*766Speter case TBOOL: 949*766Speter case TCHAR: 950*766Speter case TINT: 951*766Speter case TSCAL: 952*766Speter postcheck( ap ); 953*766Speter /* and fall through */ 954*766Speter case TDOUBLE: 955*766Speter case TPTR: 956*766Speter putop( P2ASSIGN , p2type( ap ) ); 957*766Speter putdot( filename , line ); 958*766Speter break; 959*766Speter default: 960*766Speter putstrop( P2STASG 961*766Speter , p2type( ap ) 962*766Speter , lwidth( ap ) 963*766Speter , align( ap ) ); 964*766Speter putdot( filename , line ); 965*766Speter break; 966*766Speter } 967*766Speter /* 968*766Speter * get(file); 969*766Speter */ 970*766Speter putleaf( P2ICON , 0 , 0 971*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 972*766Speter , "_GET" ); 973*766Speter putRV( 0 , cbn , CURFILEOFFSET 974*766Speter , P2PTR|P2STRTY ); 975*766Speter putop( P2CALL , P2INT ); 976*766Speter putdot( filename , line ); 977*766Speter continue; 978*766Speter } 979*766Speter /* 980*766Speter * if you get to here, you are reading from 981*766Speter * a text file. only possiblities are: 982*766Speter * character, integer, real, or scalar. 983*766Speter * read( f , foo , ... ) is done as 984*766Speter * foo := read( f ) with rangechecking 985*766Speter * if appropriate. 986*766Speter */ 987*766Speter typ = classify(ap); 988*766Speter op = rdops(typ); 989*766Speter if (op == NIL) { 990*766Speter error("Can't read %ss from a text file", clnames[typ]); 991*766Speter continue; 992*766Speter } 993*766Speter /* 994*766Speter * left hand side of foo := read( f ) 995*766Speter */ 996*766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 997*766Speter if ( isa( ap , "bsci" ) ) { 998*766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 999*766Speter } 1000*766Speter switch ( op ) { 1001*766Speter case O_READC: 1002*766Speter readname = "_READC"; 1003*766Speter readtype = P2INT; 1004*766Speter break; 1005*766Speter case O_READ4: 1006*766Speter readname = "_READ4"; 1007*766Speter readtype = P2INT; 1008*766Speter break; 1009*766Speter case O_READ8: 1010*766Speter readname = "_READ8"; 1011*766Speter readtype = P2DOUBLE; 1012*766Speter break; 1013*766Speter case O_READE: 1014*766Speter readname = "_READE"; 1015*766Speter readtype = P2INT; 1016*766Speter break; 1017*766Speter } 1018*766Speter putleaf( P2ICON , 0 , 0 1019*766Speter , ADDTYPE( P2FTN | readtype , P2PTR ) 1020*766Speter , readname ); 1021*766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 1022*766Speter if ( op == O_READE ) { 1023*766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1024*766Speter , listnames( ap ) ); 1025*766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 1026*766Speter , format ); 1027*766Speter putop( P2LISTOP , P2INT ); 1028*766Speter if (opt('s')) { 1029*766Speter standard(); 1030*766Speter error("Reading of enumerated types is non-standard"); 1031*766Speter } 1032*766Speter } 1033*766Speter putop( P2CALL , readtype ); 1034*766Speter if ( isa( ap , "bcsi" ) ) { 1035*766Speter postcheck( ap ); 1036*766Speter } 1037*766Speter putop( P2ASSIGN , p2type( ap ) ); 1038*766Speter putdot( filename , line ); 1039*766Speter } 1040*766Speter /* 1041*766Speter * Done with arguments. 1042*766Speter * Handle readln and 1043*766Speter * insufficient number of args. 1044*766Speter */ 1045*766Speter if (p->value[0] == O_READLN) { 1046*766Speter if (filetype != nl+T1CHAR) 1047*766Speter error("Can't 'readln' a non text file"); 1048*766Speter putleaf( P2ICON , 0 , 0 1049*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1050*766Speter , "_READLN" ); 1051*766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 1052*766Speter putop( P2CALL , P2INT ); 1053*766Speter putdot( filename , line ); 1054*766Speter } else if (argc == 0) 1055*766Speter error("read requires an argument"); 1056*766Speter return; 1057*766Speter 1058*766Speter case O_GET: 1059*766Speter case O_PUT: 1060*766Speter if (argc != 1) { 1061*766Speter error("%s expects one argument", p->symbol); 1062*766Speter return; 1063*766Speter } 1064*766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 1065*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1066*766Speter , "_UNIT" ); 1067*766Speter ap = stklval(argv[1], NOFLAGS); 1068*766Speter if (ap == NIL) 1069*766Speter return; 1070*766Speter if (ap->class != FILET) { 1071*766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1072*766Speter return; 1073*766Speter } 1074*766Speter putop( P2CALL , P2INT ); 1075*766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1076*766Speter putdot( filename , line ); 1077*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1078*766Speter , op == O_GET ? "_GET" : "_PUT" ); 1079*766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 1080*766Speter putop( P2CALL , P2INT ); 1081*766Speter putdot( filename , line ); 1082*766Speter return; 1083*766Speter 1084*766Speter case O_RESET: 1085*766Speter case O_REWRITE: 1086*766Speter if (argc == 0 || argc > 2) { 1087*766Speter error("%s expects one or two arguments", p->symbol); 1088*766Speter return; 1089*766Speter } 1090*766Speter if (opt('s') && argc == 2) { 1091*766Speter standard(); 1092*766Speter error("Two argument forms of reset and rewrite are non-standard"); 1093*766Speter } 1094*766Speter putleaf( P2ICON , 0 , 0 , P2INT 1095*766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 1096*766Speter ap = stklval(argv[1], MOD|NOUSE); 1097*766Speter if (ap == NIL) 1098*766Speter return; 1099*766Speter if (ap->class != FILET) { 1100*766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1101*766Speter return; 1102*766Speter } 1103*766Speter if (argc == 2) { 1104*766Speter /* 1105*766Speter * Optional second argument 1106*766Speter * is a string name of a 1107*766Speter * UNIX (R) file to be associated. 1108*766Speter */ 1109*766Speter al = argv[2]; 1110*766Speter al = stkrval(al[1], NOFLAGS , RREQ ); 1111*766Speter if (al == NIL) 1112*766Speter return; 1113*766Speter if (classify(al) != TSTR) { 1114*766Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 1115*766Speter return; 1116*766Speter } 1117*766Speter strnglen = width(al); 1118*766Speter } else { 1119*766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 1120*766Speter strnglen = 0; 1121*766Speter } 1122*766Speter putop( P2LISTOP , P2INT ); 1123*766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 1124*766Speter putop( P2LISTOP , P2INT ); 1125*766Speter putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 ); 1126*766Speter putop( P2LISTOP , P2INT ); 1127*766Speter putop( P2CALL , P2INT ); 1128*766Speter putdot( filename , line ); 1129*766Speter return; 1130*766Speter 1131*766Speter case O_NEW: 1132*766Speter case O_DISPOSE: 1133*766Speter if (argc == 0) { 1134*766Speter error("%s expects at least one argument", p->symbol); 1135*766Speter return; 1136*766Speter } 1137*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1138*766Speter , op == O_DISPOSE ? "_DISPOSE" : 1139*766Speter opt('t') ? "_NEWZ" : "_NEW" ); 1140*766Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1141*766Speter if (ap == NIL) 1142*766Speter return; 1143*766Speter if (ap->class != PTR) { 1144*766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1145*766Speter return; 1146*766Speter } 1147*766Speter ap = ap->type; 1148*766Speter if (ap == NIL) 1149*766Speter return; 1150*766Speter argv = argv[2]; 1151*766Speter if (argv != NIL) { 1152*766Speter if (ap->class != RECORD) { 1153*766Speter error("Record required when specifying variant tags"); 1154*766Speter return; 1155*766Speter } 1156*766Speter for (; argv != NIL; argv = argv[2]) { 1157*766Speter if (ap->ptr[NL_VARNT] == NIL) { 1158*766Speter error("Too many tag fields"); 1159*766Speter return; 1160*766Speter } 1161*766Speter if (!isconst(argv[1])) { 1162*766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1163*766Speter return; 1164*766Speter } 1165*766Speter gconst(argv[1]); 1166*766Speter if (con.ctype == NIL) 1167*766Speter return; 1168*766Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 1169*766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1170*766Speter return; 1171*766Speter } 1172*766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1173*766Speter if (ap->range[0] == con.crval) 1174*766Speter break; 1175*766Speter if (ap == NIL) { 1176*766Speter error("No variant case label value equals specified constant value"); 1177*766Speter return; 1178*766Speter } 1179*766Speter ap = ap->ptr[NL_VTOREC]; 1180*766Speter } 1181*766Speter } 1182*766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1183*766Speter putop( P2LISTOP , P2INT ); 1184*766Speter putop( P2CALL , P2INT ); 1185*766Speter putdot( filename , line ); 1186*766Speter return; 1187*766Speter 1188*766Speter case O_DATE: 1189*766Speter case O_TIME: 1190*766Speter if (argc != 1) { 1191*766Speter error("%s expects one argument", p->symbol); 1192*766Speter return; 1193*766Speter } 1194*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1195*766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 1196*766Speter ap = stklval(argv[1], MOD|NOUSE); 1197*766Speter if (ap == NIL) 1198*766Speter return; 1199*766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1200*766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1201*766Speter return; 1202*766Speter } 1203*766Speter putop( P2CALL , P2INT ); 1204*766Speter putdot( filename , line ); 1205*766Speter return; 1206*766Speter 1207*766Speter case O_HALT: 1208*766Speter if (argc != 0) { 1209*766Speter error("halt takes no arguments"); 1210*766Speter return; 1211*766Speter } 1212*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1213*766Speter , "_HALT" ); 1214*766Speter 1215*766Speter putop( P2UNARY P2CALL , P2INT ); 1216*766Speter putdot( filename , line ); 1217*766Speter noreach = 1; 1218*766Speter return; 1219*766Speter 1220*766Speter case O_ARGV: 1221*766Speter if (argc != 2) { 1222*766Speter error("argv takes two arguments"); 1223*766Speter return; 1224*766Speter } 1225*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1226*766Speter , "_ARGV" ); 1227*766Speter ap = stkrval(argv[1], NIL , RREQ ); 1228*766Speter if (ap == NIL) 1229*766Speter return; 1230*766Speter if (isnta(ap, "i")) { 1231*766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1232*766Speter return; 1233*766Speter } 1234*766Speter al = argv[2]; 1235*766Speter ap = stklval(al[1], MOD|NOUSE); 1236*766Speter if (ap == NIL) 1237*766Speter return; 1238*766Speter if (classify(ap) != TSTR) { 1239*766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1240*766Speter return; 1241*766Speter } 1242*766Speter putop( P2LISTOP , P2INT ); 1243*766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1244*766Speter putop( P2LISTOP , P2INT ); 1245*766Speter putop( P2CALL , P2INT ); 1246*766Speter putdot( filename , line ); 1247*766Speter return; 1248*766Speter 1249*766Speter case O_STLIM: 1250*766Speter if (argc != 1) { 1251*766Speter error("stlimit requires one argument"); 1252*766Speter return; 1253*766Speter } 1254*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1255*766Speter , "_STLIM" ); 1256*766Speter ap = stkrval(argv[1], NIL , RREQ ); 1257*766Speter if (ap == NIL) 1258*766Speter return; 1259*766Speter if (isnta(ap, "i")) { 1260*766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1261*766Speter return; 1262*766Speter } 1263*766Speter putop( P2CALL , P2INT ); 1264*766Speter putdot( filename , line ); 1265*766Speter return; 1266*766Speter 1267*766Speter case O_REMOVE: 1268*766Speter if (argc != 1) { 1269*766Speter error("remove expects one argument"); 1270*766Speter return; 1271*766Speter } 1272*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1273*766Speter , "_REMOVE" ); 1274*766Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 1275*766Speter if (ap == NIL) 1276*766Speter return; 1277*766Speter if (classify(ap) != TSTR) { 1278*766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1279*766Speter return; 1280*766Speter } 1281*766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1282*766Speter putop( P2LISTOP , P2INT ); 1283*766Speter putop( P2CALL , P2INT ); 1284*766Speter putdot( filename , line ); 1285*766Speter return; 1286*766Speter 1287*766Speter case O_LLIMIT: 1288*766Speter if (argc != 2) { 1289*766Speter error("linelimit expects two arguments"); 1290*766Speter return; 1291*766Speter } 1292*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1293*766Speter , "_LLIMIT" ); 1294*766Speter ap = stklval(argv[1], NOFLAGS|NOUSE); 1295*766Speter if (ap == NIL) 1296*766Speter return; 1297*766Speter if (!text(ap)) { 1298*766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1299*766Speter return; 1300*766Speter } 1301*766Speter al = argv[2]; 1302*766Speter ap = stkrval(al[1], NIL , RREQ ); 1303*766Speter if (ap == NIL) 1304*766Speter return; 1305*766Speter if (isnta(ap, "i")) { 1306*766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1307*766Speter return; 1308*766Speter } 1309*766Speter putop( P2LISTOP , P2INT ); 1310*766Speter putop( P2CALL , P2INT ); 1311*766Speter putdot( filename , line ); 1312*766Speter return; 1313*766Speter case O_PAGE: 1314*766Speter if (argc != 1) { 1315*766Speter error("page expects one argument"); 1316*766Speter return; 1317*766Speter } 1318*766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 1319*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1320*766Speter , "_UNIT" ); 1321*766Speter ap = stklval(argv[1], NOFLAGS); 1322*766Speter if (ap == NIL) 1323*766Speter return; 1324*766Speter if (!text(ap)) { 1325*766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1326*766Speter return; 1327*766Speter } 1328*766Speter putop( P2CALL , P2INT ); 1329*766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1330*766Speter putdot( filename , line ); 1331*766Speter if ( opt( 't' ) ) { 1332*766Speter putleaf( P2ICON , 0 , 0 1333*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1334*766Speter , "_PAGE" ); 1335*766Speter putRV( 0 , cbn , CURFILEOFFSET 1336*766Speter , P2PTR|P2STRTY ); 1337*766Speter } else { 1338*766Speter putleaf( P2ICON , 0 , 0 1339*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1340*766Speter , "_fputc" ); 1341*766Speter putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 ); 1342*766Speter putleaf( P2ICON , 0 , 0 1343*766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1344*766Speter , "_ACTFILE" ); 1345*766Speter putRV( 0 , cbn , CURFILEOFFSET 1346*766Speter , P2PTR|P2STRTY ); 1347*766Speter putop( P2CALL , P2INT ); 1348*766Speter putop( P2LISTOP , P2INT ); 1349*766Speter } 1350*766Speter putop( P2CALL , P2INT ); 1351*766Speter putdot( filename , line ); 1352*766Speter return; 1353*766Speter 1354*766Speter case O_PACK: 1355*766Speter if (argc != 3) { 1356*766Speter error("pack expects three arguments"); 1357*766Speter return; 1358*766Speter } 1359*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1360*766Speter , "_PACK" ); 1361*766Speter pu = "pack(a,i,z)"; 1362*766Speter pua = (al = argv)[1]; 1363*766Speter pui = (al = al[2])[1]; 1364*766Speter puz = (al = al[2])[1]; 1365*766Speter goto packunp; 1366*766Speter case O_UNPACK: 1367*766Speter if (argc != 3) { 1368*766Speter error("unpack expects three arguments"); 1369*766Speter return; 1370*766Speter } 1371*766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1372*766Speter , "_UNPACK" ); 1373*766Speter pu = "unpack(z,a,i)"; 1374*766Speter puz = (al = argv)[1]; 1375*766Speter pua = (al = al[2])[1]; 1376*766Speter pui = (al = al[2])[1]; 1377*766Speter packunp: 1378*766Speter ap = stkrval((int *) pui, NLNIL , RREQ ); 1379*766Speter if (ap == NIL) 1380*766Speter return; 1381*766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1382*766Speter if (ap == NIL) 1383*766Speter return; 1384*766Speter if (ap->class != ARRAY) { 1385*766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1386*766Speter return; 1387*766Speter } 1388*766Speter putop( P2LISTOP , P2INT ); 1389*766Speter al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1390*766Speter if (al->class != ARRAY) { 1391*766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1392*766Speter return; 1393*766Speter } 1394*766Speter if (al->type == NIL || ap->type == NIL) 1395*766Speter return; 1396*766Speter if (al->type != ap->type) { 1397*766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1398*766Speter return; 1399*766Speter } 1400*766Speter putop( P2LISTOP , P2INT ); 1401*766Speter k = width(al); 1402*766Speter itemwidth = width(ap->type); 1403*766Speter ap = ap->chain; 1404*766Speter al = al->chain; 1405*766Speter if (ap->chain != NIL || al->chain != NIL) { 1406*766Speter error("%s requires a and z to be single dimension arrays", pu); 1407*766Speter return; 1408*766Speter } 1409*766Speter if (ap == NIL || al == NIL) 1410*766Speter return; 1411*766Speter /* 1412*766Speter * al is the range for z i.e. u..v 1413*766Speter * ap is the range for a i.e. m..n 1414*766Speter * i will be n-m+1 1415*766Speter * j will be v-u+1 1416*766Speter */ 1417*766Speter i = ap->range[1] - ap->range[0] + 1; 1418*766Speter j = al->range[1] - al->range[0] + 1; 1419*766Speter if (i < j) { 1420*766Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1421*766Speter return; 1422*766Speter } 1423*766Speter /* 1424*766Speter * get n-m-(v-u) and m for the interpreter 1425*766Speter */ 1426*766Speter i -= j; 1427*766Speter j = ap->range[0]; 1428*766Speter putleaf( P2ICON , itemwidth , 0 , P2INT , 0 ); 1429*766Speter putop( P2LISTOP , P2INT ); 1430*766Speter putleaf( P2ICON , j , 0 , P2INT , 0 ); 1431*766Speter putop( P2LISTOP , P2INT ); 1432*766Speter putleaf( P2ICON , i , 0 , P2INT , 0 ); 1433*766Speter putop( P2LISTOP , P2INT ); 1434*766Speter putleaf( P2ICON , k , 0 , P2INT , 0 ); 1435*766Speter putop( P2LISTOP , P2INT ); 1436*766Speter putop( P2CALL , P2INT ); 1437*766Speter putdot( filename , line ); 1438*766Speter return; 1439*766Speter case 0: 1440*766Speter error("%s is an unimplemented 6400 extension", p->symbol); 1441*766Speter return; 1442*766Speter 1443*766Speter default: 1444*766Speter panic("proc case"); 1445*766Speter } 1446*766Speter } 1447*766Speter #endif PC 1448