1766Speter /* Copyright (c) 1979 Regents of the University of California */ 2766Speter 3*9229Smckusick static char sccsid[] = "@(#)pcproc.c 1.14 11/14/82"; 4766Speter 5766Speter #include "whoami.h" 6766Speter #ifdef PC 7766Speter /* 8766Speter * and to the end of the file 9766Speter */ 10766Speter #include "0.h" 11766Speter #include "tree.h" 12766Speter #include "opcode.h" 13766Speter #include "pc.h" 14766Speter #include "pcops.h" 15766Speter 16766Speter /* 17*9229Smckusick * The constant REALSPC defines the amount of forced padding preceeding 18*9229Smckusick * real numbers when they are printed. If REALSPC == 0, then no padding 19*9229Smckusick * is added, REALSPC == 1 adds one extra blank irregardless of the width 20*9229Smckusick * specified by the user. 21*9229Smckusick * 22*9229Smckusick * N.B. - Values greater than one require program mods. 23*9229Smckusick */ 24*9229Smckusick #define REALSPC 0 25*9229Smckusick 26*9229Smckusick /* 27766Speter * The following array is used to determine which classes may be read 28766Speter * from textfiles. It is indexed by the return value from classify. 29766Speter */ 30766Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 31766Speter 32766Speter int rdxxxx[] = { 33766Speter 0, /* -7 file types */ 34766Speter 0, /* -6 record types */ 35766Speter 0, /* -5 array types */ 36766Speter O_READE, /* -4 scalar types */ 37766Speter 0, /* -3 pointer types */ 38766Speter 0, /* -2 set types */ 39766Speter 0, /* -1 string types */ 40766Speter 0, /* 0 nil, no type */ 41766Speter O_READE, /* 1 boolean */ 42766Speter O_READC, /* 2 character */ 43766Speter O_READ4, /* 3 integer */ 44766Speter O_READ8 /* 4 real */ 45766Speter }; 46766Speter 47766Speter /* 48766Speter * Proc handles procedure calls. 49766Speter * Non-builtin procedures are "buck-passed" to func (with a flag 50766Speter * indicating that they are actually procedures. 51766Speter * builtin procedures are handled here. 52766Speter */ 53766Speter pcproc(r) 54766Speter int *r; 55766Speter { 56766Speter register struct nl *p; 57766Speter register int *alv, *al, op; 58766Speter struct nl *filetype, *ap; 59766Speter int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file; 607967Smckusick char fmt, format[20], *strptr, *cmd; 61766Speter int prec, field, strnglen, fmtlen, fmtstart, pu; 62766Speter int *pua, *pui, *puz; 63766Speter int i, j, k; 64766Speter int itemwidth; 653833Speter char *readname; 663833Speter struct nl *tempnlp; 673833Speter long readtype; 683833Speter struct tmps soffset; 69766Speter 70766Speter #define CONPREC 4 71766Speter #define VARPREC 8 72766Speter #define CONWIDTH 1 73766Speter #define VARWIDTH 2 74766Speter #define SKIP 16 75766Speter 76766Speter /* 77766Speter * Verify that the name is 78766Speter * defined and is that of a 79766Speter * procedure. 80766Speter */ 81766Speter p = lookup(r[2]); 82766Speter if (p == NIL) { 83766Speter rvlist(r[3]); 84766Speter return; 85766Speter } 861197Speter if (p->class != PROC && p->class != FPROC) { 87766Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 88766Speter rvlist(r[3]); 89766Speter return; 90766Speter } 91766Speter argv = r[3]; 92766Speter 93766Speter /* 94766Speter * Call handles user defined 95766Speter * procedures and functions. 96766Speter */ 97766Speter if (bn != 0) { 98766Speter call(p, argv, PROC, bn); 99766Speter return; 100766Speter } 101766Speter 102766Speter /* 103766Speter * Call to built-in procedure. 104766Speter * Count the arguments. 105766Speter */ 106766Speter argc = 0; 107766Speter for (al = argv; al != NIL; al = al[2]) 108766Speter argc++; 109766Speter 110766Speter /* 111766Speter * Switch on the operator 112766Speter * associated with the built-in 113766Speter * procedure in the namelist 114766Speter */ 115766Speter op = p->value[0] &~ NSTAND; 116766Speter if (opt('s') && (p->value[0] & NSTAND)) { 117766Speter standard(); 118766Speter error("%s is a nonstandard procedure", p->symbol); 119766Speter } 120766Speter switch (op) { 121766Speter 122766Speter case O_ABORT: 123766Speter if (argc != 0) 124766Speter error("null takes no arguments"); 125766Speter return; 126766Speter 127766Speter case O_FLUSH: 128766Speter if (argc == 0) { 129766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 130766Speter putop( P2UNARY P2CALL , P2INT ); 131766Speter putdot( filename , line ); 132766Speter return; 133766Speter } 134766Speter if (argc != 1) { 135766Speter error("flush takes at most one argument"); 136766Speter return; 137766Speter } 138766Speter putleaf( P2ICON , 0 , 0 139766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 140766Speter , "_FLUSH" ); 141766Speter ap = stklval(argv[1], NOFLAGS); 142766Speter if (ap == NIL) 143766Speter return; 144766Speter if (ap->class != FILET) { 145766Speter error("flush's argument must be a file, not %s", nameof(ap)); 146766Speter return; 147766Speter } 148766Speter putop( P2CALL , P2INT ); 149766Speter putdot( filename , line ); 150766Speter return; 151766Speter 152766Speter case O_MESSAGE: 153766Speter case O_WRITEF: 154766Speter case O_WRITLN: 155766Speter /* 156766Speter * Set up default file "output"'s type 157766Speter */ 158766Speter file = NIL; 159766Speter filetype = nl+T1CHAR; 160766Speter /* 161766Speter * Determine the file implied 162766Speter * for the write and generate 163766Speter * code to make it the active file. 164766Speter */ 165766Speter if (op == O_MESSAGE) { 166766Speter /* 167766Speter * For message, all that matters 168766Speter * is that the filetype is 169766Speter * a character file. 170766Speter * Thus "output" will suit us fine. 171766Speter */ 172766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 173766Speter putop( P2UNARY P2CALL , P2INT ); 174766Speter putdot( filename , line ); 1753833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 1763833Speter P2PTR|P2STRTY ); 1773833Speter putLV( "__err" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 178766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 179766Speter putdot( filename , line ); 180766Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 181766Speter /* 182766Speter * If there is a first argument which has 183766Speter * no write widths, then it is potentially 184766Speter * a file name. 185766Speter */ 186766Speter codeoff(); 187766Speter ap = stkrval(argv[1], NIL , RREQ ); 188766Speter codeon(); 189766Speter if (ap == NIL) 190766Speter argv = argv[2]; 191766Speter if (ap != NIL && ap->class == FILET) { 192766Speter /* 193766Speter * Got "write(f, ...", make 194766Speter * f the active file, and save 195766Speter * it and its type for use in 196766Speter * processing the rest of the 197766Speter * arguments to write. 198766Speter */ 1993833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 2003833Speter P2PTR|P2STRTY ); 201766Speter putleaf( P2ICON , 0 , 0 202766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 203766Speter , "_UNIT" ); 204766Speter file = argv[1]; 205766Speter filetype = ap->type; 206766Speter stklval(argv[1], NOFLAGS); 207766Speter putop( P2CALL , P2INT ); 208766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 209766Speter putdot( filename , line ); 210766Speter /* 211766Speter * Skip over the first argument 212766Speter */ 213766Speter argv = argv[2]; 214766Speter argc--; 215766Speter } else { 216766Speter /* 217766Speter * Set up for writing on 218766Speter * standard output. 219766Speter */ 2203833Speter putRV( 0, cbn , CURFILEOFFSET , 2213833Speter NLOCAL , P2PTR|P2STRTY ); 2223833Speter putLV( "_output" , 0 , 0 , NGLOBAL , 2233833Speter P2PTR|P2STRTY ); 224766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 225766Speter putdot( filename , line ); 2267954Speter output->nl_flags |= NUSED; 227766Speter } 228766Speter } else { 2293833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 2303833Speter P2PTR|P2STRTY ); 2313833Speter putLV( "_output" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 232766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 233766Speter putdot( filename , line ); 2347954Speter output->nl_flags |= NUSED; 235766Speter } 236766Speter /* 237766Speter * Loop and process each 238766Speter * of the arguments. 239766Speter */ 240766Speter for (; argv != NIL; argv = argv[2]) { 241766Speter /* 242766Speter * fmtspec indicates the type (CONstant or VARiable) 243766Speter * and number (none, WIDTH, and/or PRECision) 244766Speter * of the fields in the printf format for this 245766Speter * output variable. 246766Speter * stkcnt is the number of longs pushed on the stack 247766Speter * fmt is the format output indicator (D, E, F, O, X, S) 248766Speter * fmtstart = 0 for leading blank; = 1 for no blank 249766Speter */ 250766Speter fmtspec = NIL; 251766Speter stkcnt = 0; 252766Speter fmt = 'D'; 253766Speter fmtstart = 1; 254766Speter al = argv[1]; 255766Speter if (al == NIL) 256766Speter continue; 257766Speter if (al[0] == T_WEXP) 258766Speter alv = al[1]; 259766Speter else 260766Speter alv = al; 261766Speter if (alv == NIL) 262766Speter continue; 263766Speter codeoff(); 264766Speter ap = stkrval(alv, NIL , RREQ ); 265766Speter codeon(); 266766Speter if (ap == NIL) 267766Speter continue; 268766Speter typ = classify(ap); 269766Speter if (al[0] == T_WEXP) { 270766Speter /* 271766Speter * Handle width expressions. 272766Speter * The basic game here is that width 273766Speter * expressions get evaluated. If they 274766Speter * are constant, the value is placed 275766Speter * directly in the format string. 276766Speter * Otherwise the value is pushed onto 277766Speter * the stack and an indirection is 278766Speter * put into the format string. 279766Speter */ 280766Speter if (al[3] == OCT) 281766Speter fmt = 'O'; 282766Speter else if (al[3] == HEX) 283766Speter fmt = 'X'; 284766Speter else if (al[3] != NIL) { 285766Speter /* 286766Speter * Evaluate second format spec 287766Speter */ 288766Speter if ( constval(al[3]) 289766Speter && isa( con.ctype , "i" ) ) { 290766Speter fmtspec += CONPREC; 291766Speter prec = con.crval; 292766Speter } else { 293766Speter fmtspec += VARPREC; 294766Speter } 295766Speter fmt = 'f'; 296766Speter switch ( typ ) { 297766Speter case TINT: 298766Speter if ( opt( 's' ) ) { 299766Speter standard(); 300766Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 301766Speter } 302766Speter /* and fall through */ 303766Speter case TDOUBLE: 304766Speter break; 305766Speter default: 306766Speter error("Cannot write %ss with two write widths", clnames[typ]); 307766Speter continue; 308766Speter } 309766Speter } 310766Speter /* 311766Speter * Evaluate first format spec 312766Speter */ 313766Speter if (al[2] != NIL) { 314766Speter if ( constval(al[2]) 315766Speter && isa( con.ctype , "i" ) ) { 316766Speter fmtspec += CONWIDTH; 317766Speter field = con.crval; 318766Speter } else { 319766Speter fmtspec += VARWIDTH; 320766Speter } 321766Speter } 322766Speter if ((fmtspec & CONPREC) && prec < 0 || 323766Speter (fmtspec & CONWIDTH) && field < 0) { 324766Speter error("Negative widths are not allowed"); 325766Speter continue; 326766Speter } 3273180Smckusic if ( opt('s') && 3283180Smckusic ((fmtspec & CONPREC) && prec == 0 || 3293180Smckusic (fmtspec & CONWIDTH) && field == 0)) { 3303180Smckusic standard(); 3313180Smckusic error("Zero widths are non-standard"); 3323180Smckusic } 333766Speter } 334766Speter if (filetype != nl+T1CHAR) { 335766Speter if (fmt == 'O' || fmt == 'X') { 336766Speter error("Oct/hex allowed only on text files"); 337766Speter continue; 338766Speter } 339766Speter if (fmtspec) { 340766Speter error("Write widths allowed only on text files"); 341766Speter continue; 342766Speter } 343766Speter /* 344766Speter * Generalized write, i.e. 345766Speter * to a non-textfile. 346766Speter */ 347766Speter putleaf( P2ICON , 0 , 0 348766Speter , ADDTYPE( 349766Speter ADDTYPE( 350766Speter ADDTYPE( p2type( filetype ) 351766Speter , P2PTR ) 352766Speter , P2FTN ) 353766Speter , P2PTR ) 354766Speter , "_FNIL" ); 355766Speter stklval(file, NOFLAGS); 356766Speter putop( P2CALL 357766Speter , ADDTYPE( p2type( filetype ) , P2PTR ) ); 358766Speter putop( P2UNARY P2MUL , p2type( filetype ) ); 359766Speter /* 360766Speter * file^ := ... 361766Speter */ 362766Speter switch ( classify( filetype ) ) { 363766Speter case TBOOL: 364766Speter case TCHAR: 365766Speter case TINT: 366766Speter case TSCAL: 3674589Speter precheck( filetype , "_RANG4" , "_RSNG4" ); 368766Speter /* and fall through */ 369766Speter case TDOUBLE: 370766Speter case TPTR: 371766Speter ap = rvalue( argv[1] , filetype , RREQ ); 372766Speter break; 373766Speter default: 374766Speter ap = rvalue( argv[1] , filetype , LREQ ); 375766Speter break; 376766Speter } 377766Speter if (ap == NIL) 378766Speter continue; 379766Speter if (incompat(ap, filetype, argv[1])) { 380766Speter cerror("Type mismatch in write to non-text file"); 381766Speter continue; 382766Speter } 383766Speter switch ( classify( filetype ) ) { 384766Speter case TBOOL: 385766Speter case TCHAR: 386766Speter case TINT: 387766Speter case TSCAL: 388766Speter postcheck( filetype ); 389766Speter /* and fall through */ 390766Speter case TDOUBLE: 391766Speter case TPTR: 392766Speter putop( P2ASSIGN , p2type( filetype ) ); 393766Speter putdot( filename , line ); 394766Speter break; 395766Speter default: 396766Speter putstrop( P2STASG 397766Speter , p2type( filetype ) 398766Speter , lwidth( filetype ) 399766Speter , align( filetype ) ); 400766Speter putdot( filename , line ); 401766Speter break; 402766Speter } 403766Speter /* 404766Speter * put(file) 405766Speter */ 406766Speter putleaf( P2ICON , 0 , 0 407766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 408766Speter , "_PUT" ); 4093833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 4103833Speter P2PTR|P2STRTY ); 411766Speter putop( P2CALL , P2INT ); 412766Speter putdot( filename , line ); 413766Speter continue; 414766Speter } 415766Speter /* 416766Speter * Write to a textfile 417766Speter * 418766Speter * Evaluate the expression 419766Speter * to be written. 420766Speter */ 421766Speter if (fmt == 'O' || fmt == 'X') { 422766Speter if (opt('s')) { 423766Speter standard(); 424766Speter error("Oct and hex are non-standard"); 425766Speter } 426766Speter if (typ == TSTR || typ == TDOUBLE) { 427766Speter error("Can't write %ss with oct/hex", clnames[typ]); 428766Speter continue; 429766Speter } 430766Speter if (typ == TCHAR || typ == TBOOL) 431766Speter typ = TINT; 432766Speter } 433766Speter /* 434766Speter * If there is no format specified by the programmer, 435766Speter * implement the default. 436766Speter */ 437766Speter switch (typ) { 4386540Smckusick case TPTR: 4396540Smckusick warning(); 4406540Smckusick if (opt('s')) { 4416540Smckusick standard(); 4426540Smckusick } 4436540Smckusick error("Writing %ss to text files is non-standard", 4446540Smckusick clnames[typ]); 4456540Smckusick /* and fall through */ 446766Speter case TINT: 447766Speter if (fmt == 'f') { 448766Speter typ = TDOUBLE; 449766Speter goto tdouble; 450766Speter } 451766Speter if (fmtspec == NIL) { 452766Speter if (fmt == 'D') 453766Speter field = 10; 454766Speter else if (fmt == 'X') 455766Speter field = 8; 456766Speter else if (fmt == 'O') 457766Speter field = 11; 458766Speter else 459766Speter panic("fmt1"); 460766Speter fmtspec = CONWIDTH; 461766Speter } 462766Speter break; 463766Speter case TCHAR: 464766Speter tchar: 465766Speter fmt = 'c'; 466766Speter break; 467766Speter case TSCAL: 4681629Speter warning(); 469766Speter if (opt('s')) { 470766Speter standard(); 471766Speter } 4726540Smckusick error("Writing %ss to text files is non-standard", 4736540Smckusick clnames[typ]); 474766Speter case TBOOL: 475766Speter fmt = 's'; 476766Speter break; 477766Speter case TDOUBLE: 478766Speter tdouble: 479766Speter switch (fmtspec) { 480766Speter case NIL: 481766Speter field = 21; 482766Speter prec = 14; 4833225Smckusic fmt = 'e'; 484766Speter fmtspec = CONWIDTH + CONPREC; 485766Speter break; 486766Speter case CONWIDTH: 487*9229Smckusick field -= REALSPC; 488*9229Smckusick if (field < 1) 489766Speter field = 1; 490766Speter prec = field - 7; 491766Speter if (prec < 1) 492766Speter prec = 1; 493766Speter fmtspec += CONPREC; 4943225Smckusic fmt = 'e'; 495766Speter break; 496766Speter case VARWIDTH: 497766Speter fmtspec += VARPREC; 4983225Smckusic fmt = 'e'; 499766Speter break; 500766Speter case CONWIDTH + CONPREC: 501766Speter case CONWIDTH + VARPREC: 502*9229Smckusick field -= REALSPC; 503*9229Smckusick if (field < 1) 504766Speter field = 1; 505766Speter } 506766Speter format[0] = ' '; 507*9229Smckusick fmtstart = 1 - REALSPC; 508766Speter break; 509766Speter case TSTR: 510766Speter constval( alv ); 511766Speter switch ( classify( con.ctype ) ) { 512766Speter case TCHAR: 513766Speter typ = TCHAR; 514766Speter goto tchar; 515766Speter case TSTR: 516766Speter strptr = con.cpval; 517766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 518766Speter strptr = con.cpval; 519766Speter break; 520766Speter default: 521766Speter strnglen = width(ap); 522766Speter break; 523766Speter } 524766Speter fmt = 's'; 525766Speter strfmt = fmtspec; 526766Speter if (fmtspec == NIL) { 527766Speter fmtspec = SKIP; 528766Speter break; 529766Speter } 530766Speter if (fmtspec & CONWIDTH) { 531766Speter if (field <= strnglen) 532766Speter fmtspec = SKIP; 533766Speter else 534766Speter field -= strnglen; 535766Speter } 536766Speter break; 537766Speter default: 538766Speter error("Can't write %ss to a text file", clnames[typ]); 539766Speter continue; 540766Speter } 541766Speter /* 542766Speter * Generate the format string 543766Speter */ 544766Speter switch (fmtspec) { 545766Speter default: 546766Speter panic("fmt2"); 547766Speter case NIL: 548766Speter if (fmt == 'c') { 549766Speter if ( opt( 't' ) ) { 550766Speter putleaf( P2ICON , 0 , 0 551766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 552766Speter , "_WRITEC" ); 5533833Speter putRV( 0 , cbn , CURFILEOFFSET , 5543833Speter NLOCAL , P2PTR|P2STRTY ); 555766Speter stkrval( alv , NIL , RREQ ); 556766Speter putop( P2LISTOP , P2INT ); 557766Speter } else { 558766Speter putleaf( P2ICON , 0 , 0 559766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 560766Speter , "_fputc" ); 561766Speter stkrval( alv , NIL , RREQ ); 562766Speter } 563766Speter putleaf( P2ICON , 0 , 0 564766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 565766Speter , "_ACTFILE" ); 5663833Speter putRV( 0, cbn , CURFILEOFFSET , 5673833Speter NLOCAL , P2PTR|P2STRTY ); 568766Speter putop( P2CALL , P2INT ); 569766Speter putop( P2LISTOP , P2INT ); 570766Speter putop( P2CALL , P2INT ); 571766Speter putdot( filename , line ); 572766Speter } else { 573766Speter sprintf(&format[1], "%%%c", fmt); 574766Speter goto fmtgen; 575766Speter } 576766Speter case SKIP: 577766Speter break; 578766Speter case CONWIDTH: 579766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 580766Speter goto fmtgen; 581766Speter case VARWIDTH: 582766Speter sprintf(&format[1], "%%*%c", fmt); 583766Speter goto fmtgen; 584766Speter case CONWIDTH + CONPREC: 585766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 586766Speter goto fmtgen; 587766Speter case CONWIDTH + VARPREC: 588766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 589766Speter goto fmtgen; 590766Speter case VARWIDTH + CONPREC: 591766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 592766Speter goto fmtgen; 593766Speter case VARWIDTH + VARPREC: 594766Speter sprintf(&format[1], "%%*.*%c", fmt); 595766Speter fmtgen: 596766Speter if ( opt( 't' ) ) { 597766Speter putleaf( P2ICON , 0 , 0 598766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 599766Speter , "_WRITEF" ); 6003833Speter putRV( 0 , cbn , CURFILEOFFSET , 6013833Speter NLOCAL , P2PTR|P2STRTY ); 602766Speter putleaf( P2ICON , 0 , 0 603766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 604766Speter , "_ACTFILE" ); 6053833Speter putRV( 0 , cbn , CURFILEOFFSET , 6063833Speter NLOCAL , P2PTR|P2STRTY ); 607766Speter putop( P2CALL , P2INT ); 608766Speter putop( P2LISTOP , P2INT ); 609766Speter } else { 610766Speter putleaf( P2ICON , 0 , 0 611766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 612766Speter , "_fprintf" ); 613766Speter putleaf( P2ICON , 0 , 0 614766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 615766Speter , "_ACTFILE" ); 6163833Speter putRV( 0 , cbn , CURFILEOFFSET , 6173833Speter NLOCAL , P2PTR|P2STRTY ); 618766Speter putop( P2CALL , P2INT ); 619766Speter } 620766Speter putCONG( &format[ fmtstart ] 621766Speter , strlen( &format[ fmtstart ] ) 622766Speter , LREQ ); 623766Speter putop( P2LISTOP , P2INT ); 624766Speter if ( fmtspec & VARWIDTH ) { 625766Speter /* 626766Speter * either 627766Speter * ,(temp=width,MAX(temp,...)), 628766Speter * or 629766Speter * , MAX( width , ... ) , 630766Speter */ 631766Speter if ( ( typ == TDOUBLE && al[3] == NIL ) 632766Speter || typ == TSTR ) { 6333225Smckusic soffset = sizes[cbn].curtmps; 6343833Speter tempnlp = tmpalloc(sizeof(long), 6353225Smckusic nl+T4INT, REGOK); 6363833Speter putRV( 0 , cbn , 6373833Speter tempnlp -> value[ NL_OFFS ] , 6383833Speter tempnlp -> extra_flags , P2INT ); 639766Speter ap = stkrval( al[2] , NIL , RREQ ); 640766Speter putop( P2ASSIGN , P2INT ); 641766Speter putleaf( P2ICON , 0 , 0 642766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 643766Speter , "_MAX" ); 6443833Speter putRV( 0 , cbn , 6453833Speter tempnlp -> value[ NL_OFFS ] , 6463833Speter tempnlp -> extra_flags , P2INT ); 647766Speter } else { 648766Speter if (opt('t') 649766Speter || typ == TSTR || typ == TDOUBLE) { 650766Speter putleaf( P2ICON , 0 , 0 651766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 652766Speter ,"_MAX" ); 653766Speter } 654766Speter ap = stkrval( al[2] , NIL , RREQ ); 655766Speter } 656766Speter if (ap == NIL) 657766Speter continue; 658766Speter if (isnta(ap,"i")) { 659766Speter error("First write width must be integer, not %s", nameof(ap)); 660766Speter continue; 661766Speter } 662766Speter switch ( typ ) { 663766Speter case TDOUBLE: 664*9229Smckusick putleaf( P2ICON , REALSPC , 0 , P2INT , 0 ); 665766Speter putop( P2LISTOP , P2INT ); 666766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 667766Speter putop( P2LISTOP , P2INT ); 668766Speter putop( P2CALL , P2INT ); 669766Speter if ( al[3] == NIL ) { 670766Speter /* 671766Speter * finish up the comma op 672766Speter */ 673766Speter putop( P2COMOP , P2INT ); 674766Speter fmtspec &= ~VARPREC; 675766Speter putop( P2LISTOP , P2INT ); 676766Speter putleaf( P2ICON , 0 , 0 677766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 678766Speter , "_MAX" ); 6793833Speter putRV( 0 , cbn , 6803833Speter tempnlp -> value[ NL_OFFS ] , 6813833Speter tempnlp -> extra_flags , 6823833Speter P2INT ); 6833225Smckusic tmpfree(&soffset); 684*9229Smckusick putleaf( P2ICON , 7 + REALSPC , 0 , P2INT , 0 ); 685766Speter putop( P2LISTOP , P2INT ); 686766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 687766Speter putop( P2LISTOP , P2INT ); 688766Speter putop( P2CALL , P2INT ); 689766Speter } 690766Speter putop( P2LISTOP , P2INT ); 691766Speter break; 692766Speter case TSTR: 693766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 694766Speter putop( P2LISTOP , P2INT ); 695766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 696766Speter putop( P2LISTOP , P2INT ); 697766Speter putop( P2CALL , P2INT ); 698766Speter putop( P2COMOP , P2INT ); 699766Speter putop( P2LISTOP , P2INT ); 700766Speter break; 701766Speter default: 702766Speter if (opt('t')) { 703766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 704766Speter putop( P2LISTOP , P2INT ); 705766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 706766Speter putop( P2LISTOP , P2INT ); 707766Speter putop( P2CALL , P2INT ); 708766Speter } 709766Speter putop( P2LISTOP , P2INT ); 710766Speter break; 711766Speter } 712766Speter } 713766Speter /* 714766Speter * If there is a variable precision, 715766Speter * evaluate it 716766Speter */ 717766Speter if (fmtspec & VARPREC) { 718766Speter if (opt('t')) { 719766Speter putleaf( P2ICON , 0 , 0 720766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 721766Speter , "_MAX" ); 722766Speter } 723766Speter ap = stkrval( al[3] , NIL , RREQ ); 724766Speter if (ap == NIL) 725766Speter continue; 726766Speter if (isnta(ap,"i")) { 727766Speter error("Second write width must be integer, not %s", nameof(ap)); 728766Speter continue; 729766Speter } 730766Speter if (opt('t')) { 731766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 732766Speter putop( P2LISTOP , P2INT ); 733766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 734766Speter putop( P2LISTOP , P2INT ); 735766Speter putop( P2CALL , P2INT ); 736766Speter } 737766Speter putop( P2LISTOP , P2INT ); 738766Speter } 739766Speter /* 740766Speter * evaluate the thing we want printed. 741766Speter */ 742766Speter switch ( typ ) { 7436540Smckusick case TPTR: 744766Speter case TCHAR: 745766Speter case TINT: 746766Speter stkrval( alv , NIL , RREQ ); 747766Speter putop( P2LISTOP , P2INT ); 748766Speter break; 749766Speter case TDOUBLE: 750766Speter ap = stkrval( alv , NIL , RREQ ); 751766Speter if ( isnta( ap , "d" ) ) { 752766Speter putop( P2SCONV , P2DOUBLE ); 753766Speter } 754766Speter putop( P2LISTOP , P2INT ); 755766Speter break; 756766Speter case TSCAL: 757766Speter case TBOOL: 758766Speter putleaf( P2ICON , 0 , 0 759766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 760766Speter , "_NAM" ); 761766Speter ap = stkrval( alv , NIL , RREQ ); 762766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 763766Speter , listnames( ap ) ); 764766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 765766Speter , format ); 766766Speter putop( P2LISTOP , P2INT ); 767766Speter putop( P2CALL , P2INT ); 768766Speter putop( P2LISTOP , P2INT ); 769766Speter break; 770766Speter case TSTR: 771766Speter putCONG( "" , 0 , LREQ ); 772766Speter putop( P2LISTOP , P2INT ); 773766Speter break; 7746540Smckusick default: 7756540Smckusick panic("fmt3"); 7766540Smckusick break; 777766Speter } 778766Speter putop( P2CALL , P2INT ); 779766Speter putdot( filename , line ); 780766Speter } 781766Speter /* 782766Speter * Write the string after its blank padding 783766Speter */ 784766Speter if (typ == TSTR ) { 785766Speter if ( opt( 't' ) ) { 786766Speter putleaf( P2ICON , 0 , 0 787766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 788766Speter , "_WRITES" ); 7893833Speter putRV( 0 , cbn , CURFILEOFFSET , 7903833Speter NLOCAL , P2PTR|P2STRTY ); 791766Speter ap = stkrval(alv, NIL , RREQ ); 792766Speter putop( P2LISTOP , P2INT ); 793766Speter } else { 794766Speter putleaf( P2ICON , 0 , 0 795766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 796766Speter , "_fwrite" ); 797766Speter ap = stkrval(alv, NIL , RREQ ); 798766Speter } 799766Speter if (strfmt & VARWIDTH) { 800766Speter /* 801766Speter * min, inline expanded as 802766Speter * temp < len ? temp : len 803766Speter */ 8043833Speter putRV( 0 , cbn , 8053833Speter tempnlp -> value[ NL_OFFS ] , 8063833Speter tempnlp -> extra_flags , P2INT ); 807766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 808766Speter putop( P2LT , P2INT ); 8093833Speter putRV( 0 , cbn , 8103833Speter tempnlp -> value[ NL_OFFS ] , 8113833Speter tempnlp -> extra_flags , P2INT ); 812766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 813766Speter putop( P2COLON , P2INT ); 814766Speter putop( P2QUEST , P2INT ); 8153225Smckusic tmpfree(&soffset); 816766Speter } else { 817766Speter if ( ( fmtspec & SKIP ) 818766Speter && ( strfmt & CONWIDTH ) ) { 819766Speter strnglen = field; 820766Speter } 821766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 822766Speter } 823766Speter putop( P2LISTOP , P2INT ); 824766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 825766Speter putop( P2LISTOP , P2INT ); 826766Speter putleaf( P2ICON , 0 , 0 827766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 828766Speter , "_ACTFILE" ); 8293833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 8303833Speter P2PTR|P2STRTY ); 831766Speter putop( P2CALL , P2INT ); 832766Speter putop( P2LISTOP , P2INT ); 833766Speter putop( P2CALL , P2INT ); 834766Speter putdot( filename , line ); 835766Speter } 836766Speter } 837766Speter /* 838766Speter * Done with arguments. 839766Speter * Handle writeln and 840766Speter * insufficent number of args. 841766Speter */ 842766Speter switch (p->value[0] &~ NSTAND) { 843766Speter case O_WRITEF: 844766Speter if (argc == 0) 845766Speter error("Write requires an argument"); 846766Speter break; 847766Speter case O_MESSAGE: 848766Speter if (argc == 0) 849766Speter error("Message requires an argument"); 850766Speter case O_WRITLN: 851766Speter if (filetype != nl+T1CHAR) 852766Speter error("Can't 'writeln' a non text file"); 853766Speter if ( opt( 't' ) ) { 854766Speter putleaf( P2ICON , 0 , 0 855766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 856766Speter , "_WRITLN" ); 8573833Speter putRV( 0 , cbn , CURFILEOFFSET , 8583833Speter NLOCAL , P2PTR|P2STRTY ); 859766Speter } else { 860766Speter putleaf( P2ICON , 0 , 0 861766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 862766Speter , "_fputc" ); 863766Speter putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 ); 864766Speter putleaf( P2ICON , 0 , 0 865766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 866766Speter , "_ACTFILE" ); 8673833Speter putRV( 0 , cbn , CURFILEOFFSET , 8683833Speter NLOCAL , P2PTR|P2STRTY ); 869766Speter putop( P2CALL , P2INT ); 870766Speter putop( P2LISTOP , P2INT ); 871766Speter } 872766Speter putop( P2CALL , P2INT ); 873766Speter putdot( filename , line ); 874766Speter break; 875766Speter } 876766Speter return; 877766Speter 878766Speter case O_READ4: 879766Speter case O_READLN: 880766Speter /* 881766Speter * Set up default 882766Speter * file "input". 883766Speter */ 884766Speter file = NIL; 885766Speter filetype = nl+T1CHAR; 886766Speter /* 887766Speter * Determine the file implied 888766Speter * for the read and generate 889766Speter * code to make it the active file. 890766Speter */ 891766Speter if (argv != NIL) { 892766Speter codeoff(); 893766Speter ap = stkrval(argv[1], NIL , RREQ ); 894766Speter codeon(); 895766Speter if (ap == NIL) 896766Speter argv = argv[2]; 897766Speter if (ap != NIL && ap->class == FILET) { 898766Speter /* 899766Speter * Got "read(f, ...", make 900766Speter * f the active file, and save 901766Speter * it and its type for use in 902766Speter * processing the rest of the 903766Speter * arguments to read. 904766Speter */ 905766Speter file = argv[1]; 906766Speter filetype = ap->type; 9073833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9083833Speter P2PTR|P2STRTY ); 909766Speter putleaf( P2ICON , 0 , 0 910766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 911766Speter , "_UNIT" ); 912766Speter stklval(argv[1], NOFLAGS); 913766Speter putop( P2CALL , P2INT ); 914766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 915766Speter putdot( filename , line ); 916766Speter argv = argv[2]; 917766Speter argc--; 918766Speter } else { 919766Speter /* 920766Speter * Default is read from 921766Speter * standard input. 922766Speter */ 9233833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9243833Speter P2PTR|P2STRTY ); 9253833Speter putLV( "_input" , 0 , 0 , NGLOBAL , 9263833Speter P2PTR|P2STRTY ); 927766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 928766Speter putdot( filename , line ); 929766Speter input->nl_flags |= NUSED; 930766Speter } 931766Speter } else { 9323833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9333833Speter P2PTR|P2STRTY ); 9343833Speter putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 935766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 936766Speter putdot( filename , line ); 937766Speter input->nl_flags |= NUSED; 938766Speter } 939766Speter /* 940766Speter * Loop and process each 941766Speter * of the arguments. 942766Speter */ 943766Speter for (; argv != NIL; argv = argv[2]) { 944766Speter /* 945766Speter * Get the address of the target 946766Speter * on the stack. 947766Speter */ 948766Speter al = argv[1]; 949766Speter if (al == NIL) 950766Speter continue; 951766Speter if (al[0] != T_VAR) { 952766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 953766Speter continue; 954766Speter } 955766Speter codeoff(); 956766Speter ap = stklval(al, MOD|ASGN|NOUSE); 957766Speter codeon(); 958766Speter if (ap == NIL) 959766Speter continue; 960766Speter if (filetype != nl+T1CHAR) { 961766Speter /* 962766Speter * Generalized read, i.e. 963766Speter * from a non-textfile. 964766Speter */ 965766Speter if (incompat(filetype, ap, argv[1] )) { 966766Speter error("Type mismatch in read from non-text file"); 967766Speter continue; 968766Speter } 969766Speter /* 970766Speter * var := file ^; 971766Speter */ 972766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 973766Speter if ( isa( ap , "bsci" ) ) { 974766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 975766Speter } 976766Speter putleaf( P2ICON , 0 , 0 977766Speter , ADDTYPE( 978766Speter ADDTYPE( 979766Speter ADDTYPE( 980766Speter p2type( filetype ) , P2PTR ) 981766Speter , P2FTN ) 982766Speter , P2PTR ) 983766Speter , "_FNIL" ); 984766Speter if (file != NIL) 985766Speter stklval(file, NOFLAGS); 986766Speter else /* Magic */ 9873833Speter putRV( "_input" , 0 , 0 , NGLOBAL , 9883833Speter P2PTR | P2STRTY ); 989766Speter putop( P2CALL , P2INT ); 990766Speter switch ( classify( filetype ) ) { 991766Speter case TBOOL: 992766Speter case TCHAR: 993766Speter case TINT: 994766Speter case TSCAL: 995766Speter case TDOUBLE: 996766Speter case TPTR: 997766Speter putop( P2UNARY P2MUL 998766Speter , p2type( filetype ) ); 999766Speter } 1000766Speter switch ( classify( filetype ) ) { 1001766Speter case TBOOL: 1002766Speter case TCHAR: 1003766Speter case TINT: 1004766Speter case TSCAL: 1005766Speter postcheck( ap ); 1006766Speter /* and fall through */ 1007766Speter case TDOUBLE: 1008766Speter case TPTR: 1009766Speter putop( P2ASSIGN , p2type( ap ) ); 1010766Speter putdot( filename , line ); 1011766Speter break; 1012766Speter default: 1013766Speter putstrop( P2STASG 1014766Speter , p2type( ap ) 1015766Speter , lwidth( ap ) 1016766Speter , align( ap ) ); 1017766Speter putdot( filename , line ); 1018766Speter break; 1019766Speter } 1020766Speter /* 1021766Speter * get(file); 1022766Speter */ 1023766Speter putleaf( P2ICON , 0 , 0 1024766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1025766Speter , "_GET" ); 10263833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10273833Speter P2PTR|P2STRTY ); 1028766Speter putop( P2CALL , P2INT ); 1029766Speter putdot( filename , line ); 1030766Speter continue; 1031766Speter } 1032766Speter /* 1033766Speter * if you get to here, you are reading from 1034766Speter * a text file. only possiblities are: 1035766Speter * character, integer, real, or scalar. 1036766Speter * read( f , foo , ... ) is done as 1037766Speter * foo := read( f ) with rangechecking 1038766Speter * if appropriate. 1039766Speter */ 1040766Speter typ = classify(ap); 1041766Speter op = rdops(typ); 1042766Speter if (op == NIL) { 1043766Speter error("Can't read %ss from a text file", clnames[typ]); 1044766Speter continue; 1045766Speter } 1046766Speter /* 1047766Speter * left hand side of foo := read( f ) 1048766Speter */ 1049766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 1050766Speter if ( isa( ap , "bsci" ) ) { 1051766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1052766Speter } 1053766Speter switch ( op ) { 1054766Speter case O_READC: 1055766Speter readname = "_READC"; 1056766Speter readtype = P2INT; 1057766Speter break; 1058766Speter case O_READ4: 1059766Speter readname = "_READ4"; 1060766Speter readtype = P2INT; 1061766Speter break; 1062766Speter case O_READ8: 1063766Speter readname = "_READ8"; 1064766Speter readtype = P2DOUBLE; 1065766Speter break; 1066766Speter case O_READE: 1067766Speter readname = "_READE"; 1068766Speter readtype = P2INT; 1069766Speter break; 1070766Speter } 1071766Speter putleaf( P2ICON , 0 , 0 1072766Speter , ADDTYPE( P2FTN | readtype , P2PTR ) 1073766Speter , readname ); 10743833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10753833Speter P2PTR|P2STRTY ); 1076766Speter if ( op == O_READE ) { 1077766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1078766Speter , listnames( ap ) ); 1079766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 1080766Speter , format ); 1081766Speter putop( P2LISTOP , P2INT ); 10821629Speter warning(); 1083766Speter if (opt('s')) { 1084766Speter standard(); 1085766Speter } 10861629Speter error("Reading scalars from text files is non-standard"); 1087766Speter } 1088766Speter putop( P2CALL , readtype ); 1089766Speter if ( isa( ap , "bcsi" ) ) { 1090766Speter postcheck( ap ); 1091766Speter } 1092766Speter putop( P2ASSIGN , p2type( ap ) ); 1093766Speter putdot( filename , line ); 1094766Speter } 1095766Speter /* 1096766Speter * Done with arguments. 1097766Speter * Handle readln and 1098766Speter * insufficient number of args. 1099766Speter */ 1100766Speter if (p->value[0] == O_READLN) { 1101766Speter if (filetype != nl+T1CHAR) 1102766Speter error("Can't 'readln' a non text file"); 1103766Speter putleaf( P2ICON , 0 , 0 1104766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1105766Speter , "_READLN" ); 11063833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 11073833Speter P2PTR|P2STRTY ); 1108766Speter putop( P2CALL , P2INT ); 1109766Speter putdot( filename , line ); 1110766Speter } else if (argc == 0) 1111766Speter error("read requires an argument"); 1112766Speter return; 1113766Speter 1114766Speter case O_GET: 1115766Speter case O_PUT: 1116766Speter if (argc != 1) { 1117766Speter error("%s expects one argument", p->symbol); 1118766Speter return; 1119766Speter } 11203833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1121766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1122766Speter , "_UNIT" ); 1123766Speter ap = stklval(argv[1], NOFLAGS); 1124766Speter if (ap == NIL) 1125766Speter return; 1126766Speter if (ap->class != FILET) { 1127766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1128766Speter return; 1129766Speter } 1130766Speter putop( P2CALL , P2INT ); 1131766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1132766Speter putdot( filename , line ); 1133766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1134766Speter , op == O_GET ? "_GET" : "_PUT" ); 11353833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1136766Speter putop( P2CALL , P2INT ); 1137766Speter putdot( filename , line ); 1138766Speter return; 1139766Speter 1140766Speter case O_RESET: 1141766Speter case O_REWRITE: 1142766Speter if (argc == 0 || argc > 2) { 1143766Speter error("%s expects one or two arguments", p->symbol); 1144766Speter return; 1145766Speter } 1146766Speter if (opt('s') && argc == 2) { 1147766Speter standard(); 1148766Speter error("Two argument forms of reset and rewrite are non-standard"); 1149766Speter } 1150766Speter putleaf( P2ICON , 0 , 0 , P2INT 1151766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 1152766Speter ap = stklval(argv[1], MOD|NOUSE); 1153766Speter if (ap == NIL) 1154766Speter return; 1155766Speter if (ap->class != FILET) { 1156766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1157766Speter return; 1158766Speter } 1159766Speter if (argc == 2) { 1160766Speter /* 1161766Speter * Optional second argument 1162766Speter * is a string name of a 1163766Speter * UNIX (R) file to be associated. 1164766Speter */ 1165766Speter al = argv[2]; 1166766Speter al = stkrval(al[1], NOFLAGS , RREQ ); 1167766Speter if (al == NIL) 1168766Speter return; 1169766Speter if (classify(al) != TSTR) { 1170766Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 1171766Speter return; 1172766Speter } 1173766Speter strnglen = width(al); 1174766Speter } else { 1175766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 1176766Speter strnglen = 0; 1177766Speter } 1178766Speter putop( P2LISTOP , P2INT ); 1179766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 1180766Speter putop( P2LISTOP , P2INT ); 1181766Speter putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 ); 1182766Speter putop( P2LISTOP , P2INT ); 1183766Speter putop( P2CALL , P2INT ); 1184766Speter putdot( filename , line ); 1185766Speter return; 1186766Speter 1187766Speter case O_NEW: 1188766Speter case O_DISPOSE: 1189766Speter if (argc == 0) { 1190766Speter error("%s expects at least one argument", p->symbol); 1191766Speter return; 1192766Speter } 11939139Smckusick alv = argv[1]; 11947967Smckusick codeoff(); 11959139Smckusick ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 11967967Smckusick codeon(); 1197766Speter if (ap == NIL) 1198766Speter return; 1199766Speter if (ap->class != PTR) { 1200766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1201766Speter return; 1202766Speter } 1203766Speter ap = ap->type; 1204766Speter if (ap == NIL) 1205766Speter return; 12069139Smckusick if (op == O_NEW) 12079139Smckusick cmd = "_NEW"; 12089139Smckusick else /* op == O_DISPOSE */ 12097967Smckusick if ((ap->nl_flags & NFILES) != 0) 12107967Smckusick cmd = "_DFDISPOSE"; 12117967Smckusick else 12127967Smckusick cmd = "_DISPOSE"; 12137967Smckusick putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd); 12149139Smckusick stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1215766Speter argv = argv[2]; 1216766Speter if (argv != NIL) { 1217766Speter if (ap->class != RECORD) { 1218766Speter error("Record required when specifying variant tags"); 1219766Speter return; 1220766Speter } 1221766Speter for (; argv != NIL; argv = argv[2]) { 1222766Speter if (ap->ptr[NL_VARNT] == NIL) { 1223766Speter error("Too many tag fields"); 1224766Speter return; 1225766Speter } 1226766Speter if (!isconst(argv[1])) { 1227766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1228766Speter return; 1229766Speter } 1230766Speter gconst(argv[1]); 1231766Speter if (con.ctype == NIL) 1232766Speter return; 1233766Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 1234766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1235766Speter return; 1236766Speter } 1237766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1238766Speter if (ap->range[0] == con.crval) 1239766Speter break; 1240766Speter if (ap == NIL) { 1241766Speter error("No variant case label value equals specified constant value"); 1242766Speter return; 1243766Speter } 1244766Speter ap = ap->ptr[NL_VTOREC]; 1245766Speter } 1246766Speter } 1247766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1248766Speter putop( P2LISTOP , P2INT ); 1249766Speter putop( P2CALL , P2INT ); 1250766Speter putdot( filename , line ); 12519139Smckusick if (opt('t') && op == O_NEW) { 12529139Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 12539139Smckusick , "_blkclr" ); 12549139Smckusick stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 12559139Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 12569139Smckusick putop( P2LISTOP , P2INT ); 12579139Smckusick putop( P2CALL , P2INT ); 12589139Smckusick putdot( filename , line ); 12599139Smckusick } 1260766Speter return; 1261766Speter 1262766Speter case O_DATE: 1263766Speter case O_TIME: 1264766Speter if (argc != 1) { 1265766Speter error("%s expects one argument", p->symbol); 1266766Speter return; 1267766Speter } 1268766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1269766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 1270766Speter ap = stklval(argv[1], MOD|NOUSE); 1271766Speter if (ap == NIL) 1272766Speter return; 1273766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1274766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1275766Speter return; 1276766Speter } 1277766Speter putop( P2CALL , P2INT ); 1278766Speter putdot( filename , line ); 1279766Speter return; 1280766Speter 1281766Speter case O_HALT: 1282766Speter if (argc != 0) { 1283766Speter error("halt takes no arguments"); 1284766Speter return; 1285766Speter } 1286766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1287766Speter , "_HALT" ); 1288766Speter 1289766Speter putop( P2UNARY P2CALL , P2INT ); 1290766Speter putdot( filename , line ); 1291766Speter noreach = 1; 1292766Speter return; 1293766Speter 1294766Speter case O_ARGV: 1295766Speter if (argc != 2) { 1296766Speter error("argv takes two arguments"); 1297766Speter return; 1298766Speter } 1299766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1300766Speter , "_ARGV" ); 1301766Speter ap = stkrval(argv[1], NIL , RREQ ); 1302766Speter if (ap == NIL) 1303766Speter return; 1304766Speter if (isnta(ap, "i")) { 1305766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1306766Speter return; 1307766Speter } 1308766Speter al = argv[2]; 1309766Speter ap = stklval(al[1], MOD|NOUSE); 1310766Speter if (ap == NIL) 1311766Speter return; 1312766Speter if (classify(ap) != TSTR) { 1313766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1314766Speter return; 1315766Speter } 1316766Speter putop( P2LISTOP , P2INT ); 1317766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1318766Speter putop( P2LISTOP , P2INT ); 1319766Speter putop( P2CALL , P2INT ); 1320766Speter putdot( filename , line ); 1321766Speter return; 1322766Speter 1323766Speter case O_STLIM: 1324766Speter if (argc != 1) { 1325766Speter error("stlimit requires one argument"); 1326766Speter return; 1327766Speter } 1328766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1329766Speter , "_STLIM" ); 1330766Speter ap = stkrval(argv[1], NIL , RREQ ); 1331766Speter if (ap == NIL) 1332766Speter return; 1333766Speter if (isnta(ap, "i")) { 1334766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1335766Speter return; 1336766Speter } 1337766Speter putop( P2CALL , P2INT ); 1338766Speter putdot( filename , line ); 1339766Speter return; 1340766Speter 1341766Speter case O_REMOVE: 1342766Speter if (argc != 1) { 1343766Speter error("remove expects one argument"); 1344766Speter return; 1345766Speter } 1346766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1347766Speter , "_REMOVE" ); 1348766Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 1349766Speter if (ap == NIL) 1350766Speter return; 1351766Speter if (classify(ap) != TSTR) { 1352766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1353766Speter return; 1354766Speter } 1355766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1356766Speter putop( P2LISTOP , P2INT ); 1357766Speter putop( P2CALL , P2INT ); 1358766Speter putdot( filename , line ); 1359766Speter return; 1360766Speter 1361766Speter case O_LLIMIT: 1362766Speter if (argc != 2) { 1363766Speter error("linelimit expects two arguments"); 1364766Speter return; 1365766Speter } 1366766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1367766Speter , "_LLIMIT" ); 1368766Speter ap = stklval(argv[1], NOFLAGS|NOUSE); 1369766Speter if (ap == NIL) 1370766Speter return; 1371766Speter if (!text(ap)) { 1372766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1373766Speter return; 1374766Speter } 1375766Speter al = argv[2]; 1376766Speter ap = stkrval(al[1], NIL , RREQ ); 1377766Speter if (ap == NIL) 1378766Speter return; 1379766Speter if (isnta(ap, "i")) { 1380766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1381766Speter return; 1382766Speter } 1383766Speter putop( P2LISTOP , P2INT ); 1384766Speter putop( P2CALL , P2INT ); 1385766Speter putdot( filename , line ); 1386766Speter return; 1387766Speter case O_PAGE: 1388766Speter if (argc != 1) { 1389766Speter error("page expects one argument"); 1390766Speter return; 1391766Speter } 13923833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1393766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1394766Speter , "_UNIT" ); 1395766Speter ap = stklval(argv[1], NOFLAGS); 1396766Speter if (ap == NIL) 1397766Speter return; 1398766Speter if (!text(ap)) { 1399766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1400766Speter return; 1401766Speter } 1402766Speter putop( P2CALL , P2INT ); 1403766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1404766Speter putdot( filename , line ); 1405766Speter if ( opt( 't' ) ) { 1406766Speter putleaf( P2ICON , 0 , 0 1407766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1408766Speter , "_PAGE" ); 14093833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1410766Speter } else { 1411766Speter putleaf( P2ICON , 0 , 0 1412766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1413766Speter , "_fputc" ); 1414766Speter putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 ); 1415766Speter putleaf( P2ICON , 0 , 0 1416766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1417766Speter , "_ACTFILE" ); 14183833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1419766Speter putop( P2CALL , P2INT ); 1420766Speter putop( P2LISTOP , P2INT ); 1421766Speter } 1422766Speter putop( P2CALL , P2INT ); 1423766Speter putdot( filename , line ); 1424766Speter return; 1425766Speter 14267928Smckusick case O_ASRT: 14277928Smckusick if (!opt('t')) 14287928Smckusick return; 14297928Smckusick if (argc == 0 || argc > 2) { 14307928Smckusick error("Assert expects one or two arguments"); 14317928Smckusick return; 14327928Smckusick } 14339139Smckusick if (argc == 2) 14349139Smckusick cmd = "_ASRTS"; 14359139Smckusick else 14369139Smckusick cmd = "_ASRT"; 14377928Smckusick putleaf( P2ICON , 0 , 0 14389139Smckusick , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd ); 14397928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 14407928Smckusick if (ap == NIL) 14417928Smckusick return; 14427928Smckusick if (isnta(ap, "b")) 14437928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 14447928Smckusick if (argc == 2) { 14457928Smckusick /* 14467928Smckusick * Optional second argument is a string specifying 14477928Smckusick * why the assertion failed. 14487928Smckusick */ 14497928Smckusick al = argv[2]; 14507928Smckusick al = stkrval(al[1], NIL , RREQ ); 14517928Smckusick if (al == NIL) 14527928Smckusick return; 14537928Smckusick if (classify(al) != TSTR) { 14547928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 14557928Smckusick return; 14567928Smckusick } 14579139Smckusick putop( P2LISTOP , P2INT ); 14587928Smckusick } 14597928Smckusick putop( P2CALL , P2INT ); 14607928Smckusick putdot( filename , line ); 14617928Smckusick return; 14627928Smckusick 1463766Speter case O_PACK: 1464766Speter if (argc != 3) { 1465766Speter error("pack expects three arguments"); 1466766Speter return; 1467766Speter } 1468766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1469766Speter , "_PACK" ); 1470766Speter pu = "pack(a,i,z)"; 1471766Speter pua = (al = argv)[1]; 1472766Speter pui = (al = al[2])[1]; 1473766Speter puz = (al = al[2])[1]; 1474766Speter goto packunp; 1475766Speter case O_UNPACK: 1476766Speter if (argc != 3) { 1477766Speter error("unpack expects three arguments"); 1478766Speter return; 1479766Speter } 1480766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1481766Speter , "_UNPACK" ); 1482766Speter pu = "unpack(z,a,i)"; 1483766Speter puz = (al = argv)[1]; 1484766Speter pua = (al = al[2])[1]; 1485766Speter pui = (al = al[2])[1]; 1486766Speter packunp: 1487766Speter ap = stkrval((int *) pui, NLNIL , RREQ ); 1488766Speter if (ap == NIL) 1489766Speter return; 1490766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1491766Speter if (ap == NIL) 1492766Speter return; 1493766Speter if (ap->class != ARRAY) { 1494766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1495766Speter return; 1496766Speter } 1497766Speter putop( P2LISTOP , P2INT ); 1498766Speter al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1499766Speter if (al->class != ARRAY) { 1500766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1501766Speter return; 1502766Speter } 1503766Speter if (al->type == NIL || ap->type == NIL) 1504766Speter return; 1505766Speter if (al->type != ap->type) { 1506766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1507766Speter return; 1508766Speter } 1509766Speter putop( P2LISTOP , P2INT ); 1510766Speter k = width(al); 1511766Speter itemwidth = width(ap->type); 1512766Speter ap = ap->chain; 1513766Speter al = al->chain; 1514766Speter if (ap->chain != NIL || al->chain != NIL) { 1515766Speter error("%s requires a and z to be single dimension arrays", pu); 1516766Speter return; 1517766Speter } 1518766Speter if (ap == NIL || al == NIL) 1519766Speter return; 1520766Speter /* 1521766Speter * al is the range for z i.e. u..v 1522766Speter * ap is the range for a i.e. m..n 1523766Speter * i will be n-m+1 1524766Speter * j will be v-u+1 1525766Speter */ 1526766Speter i = ap->range[1] - ap->range[0] + 1; 1527766Speter j = al->range[1] - al->range[0] + 1; 1528766Speter if (i < j) { 1529766Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1530766Speter return; 1531766Speter } 1532766Speter /* 1533766Speter * get n-m-(v-u) and m for the interpreter 1534766Speter */ 1535766Speter i -= j; 1536766Speter j = ap->range[0]; 1537766Speter putleaf( P2ICON , itemwidth , 0 , P2INT , 0 ); 1538766Speter putop( P2LISTOP , P2INT ); 1539766Speter putleaf( P2ICON , j , 0 , P2INT , 0 ); 1540766Speter putop( P2LISTOP , P2INT ); 1541766Speter putleaf( P2ICON , i , 0 , P2INT , 0 ); 1542766Speter putop( P2LISTOP , P2INT ); 1543766Speter putleaf( P2ICON , k , 0 , P2INT , 0 ); 1544766Speter putop( P2LISTOP , P2INT ); 1545766Speter putop( P2CALL , P2INT ); 1546766Speter putdot( filename , line ); 1547766Speter return; 1548766Speter case 0: 15497928Smckusick error("%s is an unimplemented extension", p->symbol); 1550766Speter return; 1551766Speter 1552766Speter default: 1553766Speter panic("proc case"); 1554766Speter } 1555766Speter } 1556766Speter #endif PC 1557