1766Speter /* Copyright (c) 1979 Regents of the University of California */ 2766Speter 3*10373Speter static char sccsid[] = "@(#)pcproc.c 1.17 01/17/83"; 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" 1210372Speter #include "objfmt.h" 13766Speter #include "opcode.h" 1410372Speter #include "pc.h" 1510372Speter #include "pcops.h" 16766Speter 17766Speter /* 189229Smckusick * The constant REALSPC defines the amount of forced padding preceeding 199229Smckusick * real numbers when they are printed. If REALSPC == 0, then no padding 209229Smckusick * is added, REALSPC == 1 adds one extra blank irregardless of the width 219229Smckusick * specified by the user. 229229Smckusick * 239229Smckusick * N.B. - Values greater than one require program mods. 249229Smckusick */ 259229Smckusick #define REALSPC 0 269229Smckusick 279229Smckusick /* 28766Speter * The following array is used to determine which classes may be read 29766Speter * from textfiles. It is indexed by the return value from classify. 30766Speter */ 31766Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 32766Speter 33766Speter int rdxxxx[] = { 34766Speter 0, /* -7 file types */ 35766Speter 0, /* -6 record types */ 36766Speter 0, /* -5 array types */ 37766Speter O_READE, /* -4 scalar types */ 38766Speter 0, /* -3 pointer types */ 39766Speter 0, /* -2 set types */ 40766Speter 0, /* -1 string types */ 41766Speter 0, /* 0 nil, no type */ 42766Speter O_READE, /* 1 boolean */ 43766Speter O_READC, /* 2 character */ 44766Speter O_READ4, /* 3 integer */ 45766Speter O_READ8 /* 4 real */ 46766Speter }; 47766Speter 48766Speter /* 49766Speter * Proc handles procedure calls. 50766Speter * Non-builtin procedures are "buck-passed" to func (with a flag 51766Speter * indicating that they are actually procedures. 52766Speter * builtin procedures are handled here. 53766Speter */ 54766Speter pcproc(r) 55766Speter int *r; 56766Speter { 57766Speter register struct nl *p; 58766Speter register int *alv, *al, op; 59766Speter struct nl *filetype, *ap; 60766Speter int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file; 617967Smckusick char fmt, format[20], *strptr, *cmd; 62766Speter int prec, field, strnglen, fmtlen, fmtstart, pu; 63766Speter int *pua, *pui, *puz; 64766Speter int i, j, k; 65766Speter int itemwidth; 663833Speter char *readname; 673833Speter struct nl *tempnlp; 683833Speter long readtype; 693833Speter struct tmps soffset; 70766Speter 71766Speter #define CONPREC 4 72766Speter #define VARPREC 8 73766Speter #define CONWIDTH 1 74766Speter #define VARWIDTH 2 75766Speter #define SKIP 16 76766Speter 77766Speter /* 78766Speter * Verify that the name is 79766Speter * defined and is that of a 80766Speter * procedure. 81766Speter */ 82766Speter p = lookup(r[2]); 83766Speter if (p == NIL) { 84766Speter rvlist(r[3]); 85766Speter return; 86766Speter } 871197Speter if (p->class != PROC && p->class != FPROC) { 88766Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 89766Speter rvlist(r[3]); 90766Speter return; 91766Speter } 92766Speter argv = r[3]; 93766Speter 94766Speter /* 95766Speter * Call handles user defined 96766Speter * procedures and functions. 97766Speter */ 98766Speter if (bn != 0) { 99766Speter call(p, argv, PROC, bn); 100766Speter return; 101766Speter } 102766Speter 103766Speter /* 104766Speter * Call to built-in procedure. 105766Speter * Count the arguments. 106766Speter */ 107766Speter argc = 0; 108766Speter for (al = argv; al != NIL; al = al[2]) 109766Speter argc++; 110766Speter 111766Speter /* 112766Speter * Switch on the operator 113766Speter * associated with the built-in 114766Speter * procedure in the namelist 115766Speter */ 116766Speter op = p->value[0] &~ NSTAND; 117766Speter if (opt('s') && (p->value[0] & NSTAND)) { 118766Speter standard(); 119766Speter error("%s is a nonstandard procedure", p->symbol); 120766Speter } 121766Speter switch (op) { 122766Speter 123766Speter case O_ABORT: 124766Speter if (argc != 0) 125766Speter error("null takes no arguments"); 126766Speter return; 127766Speter 128766Speter case O_FLUSH: 129766Speter if (argc == 0) { 130766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 131766Speter putop( P2UNARY P2CALL , P2INT ); 132766Speter putdot( filename , line ); 133766Speter return; 134766Speter } 135766Speter if (argc != 1) { 136766Speter error("flush takes at most one argument"); 137766Speter return; 138766Speter } 139766Speter putleaf( P2ICON , 0 , 0 140766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 141766Speter , "_FLUSH" ); 142766Speter ap = stklval(argv[1], NOFLAGS); 143766Speter if (ap == NIL) 144766Speter return; 145766Speter if (ap->class != FILET) { 146766Speter error("flush's argument must be a file, not %s", nameof(ap)); 147766Speter return; 148766Speter } 149766Speter putop( P2CALL , P2INT ); 150766Speter putdot( filename , line ); 151766Speter return; 152766Speter 153766Speter case O_MESSAGE: 154766Speter case O_WRITEF: 155766Speter case O_WRITLN: 156766Speter /* 157766Speter * Set up default file "output"'s type 158766Speter */ 159766Speter file = NIL; 160766Speter filetype = nl+T1CHAR; 161766Speter /* 162766Speter * Determine the file implied 163766Speter * for the write and generate 164766Speter * code to make it the active file. 165766Speter */ 166766Speter if (op == O_MESSAGE) { 167766Speter /* 168766Speter * For message, all that matters 169766Speter * is that the filetype is 170766Speter * a character file. 171766Speter * Thus "output" will suit us fine. 172766Speter */ 173766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 174766Speter putop( P2UNARY P2CALL , P2INT ); 175766Speter putdot( filename , line ); 1763833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 1773833Speter P2PTR|P2STRTY ); 1783833Speter putLV( "__err" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 179766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 180766Speter putdot( filename , line ); 181766Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 182766Speter /* 183766Speter * If there is a first argument which has 184766Speter * no write widths, then it is potentially 185766Speter * a file name. 186766Speter */ 187766Speter codeoff(); 188766Speter ap = stkrval(argv[1], NIL , RREQ ); 189766Speter codeon(); 190766Speter if (ap == NIL) 191766Speter argv = argv[2]; 192766Speter if (ap != NIL && ap->class == FILET) { 193766Speter /* 194766Speter * Got "write(f, ...", make 195766Speter * f the active file, and save 196766Speter * it and its type for use in 197766Speter * processing the rest of the 198766Speter * arguments to write. 199766Speter */ 2003833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 2013833Speter P2PTR|P2STRTY ); 202766Speter putleaf( P2ICON , 0 , 0 203766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 204766Speter , "_UNIT" ); 205766Speter file = argv[1]; 206766Speter filetype = ap->type; 207766Speter stklval(argv[1], NOFLAGS); 208766Speter putop( P2CALL , P2INT ); 209766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 210766Speter putdot( filename , line ); 211766Speter /* 212766Speter * Skip over the first argument 213766Speter */ 214766Speter argv = argv[2]; 215766Speter argc--; 216766Speter } else { 217766Speter /* 218766Speter * Set up for writing on 219766Speter * standard output. 220766Speter */ 2213833Speter putRV( 0, cbn , CURFILEOFFSET , 2223833Speter NLOCAL , P2PTR|P2STRTY ); 2233833Speter putLV( "_output" , 0 , 0 , NGLOBAL , 2243833Speter P2PTR|P2STRTY ); 225766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 226766Speter putdot( filename , line ); 2277954Speter output->nl_flags |= NUSED; 228766Speter } 229766Speter } else { 2303833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 2313833Speter P2PTR|P2STRTY ); 2323833Speter putLV( "_output" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 233766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 234766Speter putdot( filename , line ); 2357954Speter output->nl_flags |= NUSED; 236766Speter } 237766Speter /* 238766Speter * Loop and process each 239766Speter * of the arguments. 240766Speter */ 241766Speter for (; argv != NIL; argv = argv[2]) { 242766Speter /* 243766Speter * fmtspec indicates the type (CONstant or VARiable) 244766Speter * and number (none, WIDTH, and/or PRECision) 245766Speter * of the fields in the printf format for this 246766Speter * output variable. 247766Speter * stkcnt is the number of longs pushed on the stack 248766Speter * fmt is the format output indicator (D, E, F, O, X, S) 249766Speter * fmtstart = 0 for leading blank; = 1 for no blank 250766Speter */ 251766Speter fmtspec = NIL; 252766Speter stkcnt = 0; 253766Speter fmt = 'D'; 254766Speter fmtstart = 1; 255766Speter al = argv[1]; 256766Speter if (al == NIL) 257766Speter continue; 258766Speter if (al[0] == T_WEXP) 259766Speter alv = al[1]; 260766Speter else 261766Speter alv = al; 262766Speter if (alv == NIL) 263766Speter continue; 264766Speter codeoff(); 265766Speter ap = stkrval(alv, NIL , RREQ ); 266766Speter codeon(); 267766Speter if (ap == NIL) 268766Speter continue; 269766Speter typ = classify(ap); 270766Speter if (al[0] == T_WEXP) { 271766Speter /* 272766Speter * Handle width expressions. 273766Speter * The basic game here is that width 274766Speter * expressions get evaluated. If they 275766Speter * are constant, the value is placed 276766Speter * directly in the format string. 277766Speter * Otherwise the value is pushed onto 278766Speter * the stack and an indirection is 279766Speter * put into the format string. 280766Speter */ 281766Speter if (al[3] == OCT) 282766Speter fmt = 'O'; 283766Speter else if (al[3] == HEX) 284766Speter fmt = 'X'; 285766Speter else if (al[3] != NIL) { 286766Speter /* 287766Speter * Evaluate second format spec 288766Speter */ 289766Speter if ( constval(al[3]) 290766Speter && isa( con.ctype , "i" ) ) { 291766Speter fmtspec += CONPREC; 292766Speter prec = con.crval; 293766Speter } else { 294766Speter fmtspec += VARPREC; 295766Speter } 296766Speter fmt = 'f'; 297766Speter switch ( typ ) { 298766Speter case TINT: 299766Speter if ( opt( 's' ) ) { 300766Speter standard(); 301766Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 302766Speter } 303766Speter /* and fall through */ 304766Speter case TDOUBLE: 305766Speter break; 306766Speter default: 307766Speter error("Cannot write %ss with two write widths", clnames[typ]); 308766Speter continue; 309766Speter } 310766Speter } 311766Speter /* 312766Speter * Evaluate first format spec 313766Speter */ 314766Speter if (al[2] != NIL) { 315766Speter if ( constval(al[2]) 316766Speter && isa( con.ctype , "i" ) ) { 317766Speter fmtspec += CONWIDTH; 318766Speter field = con.crval; 319766Speter } else { 320766Speter fmtspec += VARWIDTH; 321766Speter } 322766Speter } 323766Speter if ((fmtspec & CONPREC) && prec < 0 || 324766Speter (fmtspec & CONWIDTH) && field < 0) { 325766Speter error("Negative widths are not allowed"); 326766Speter continue; 327766Speter } 3283180Smckusic if ( opt('s') && 3293180Smckusic ((fmtspec & CONPREC) && prec == 0 || 3303180Smckusic (fmtspec & CONWIDTH) && field == 0)) { 3313180Smckusic standard(); 3323180Smckusic error("Zero widths are non-standard"); 3333180Smckusic } 334766Speter } 335766Speter if (filetype != nl+T1CHAR) { 336766Speter if (fmt == 'O' || fmt == 'X') { 337766Speter error("Oct/hex allowed only on text files"); 338766Speter continue; 339766Speter } 340766Speter if (fmtspec) { 341766Speter error("Write widths allowed only on text files"); 342766Speter continue; 343766Speter } 344766Speter /* 345766Speter * Generalized write, i.e. 346766Speter * to a non-textfile. 347766Speter */ 348766Speter putleaf( P2ICON , 0 , 0 349766Speter , ADDTYPE( 350766Speter ADDTYPE( 351766Speter ADDTYPE( p2type( filetype ) 352766Speter , P2PTR ) 353766Speter , P2FTN ) 354766Speter , P2PTR ) 355766Speter , "_FNIL" ); 356766Speter stklval(file, NOFLAGS); 357766Speter putop( P2CALL 358766Speter , ADDTYPE( p2type( filetype ) , P2PTR ) ); 359766Speter putop( P2UNARY P2MUL , p2type( filetype ) ); 360766Speter /* 361766Speter * file^ := ... 362766Speter */ 363766Speter switch ( classify( filetype ) ) { 364766Speter case TBOOL: 365766Speter case TCHAR: 366766Speter case TINT: 367766Speter case TSCAL: 3684589Speter precheck( filetype , "_RANG4" , "_RSNG4" ); 369766Speter /* and fall through */ 370766Speter case TDOUBLE: 371766Speter case TPTR: 372766Speter ap = rvalue( argv[1] , filetype , RREQ ); 373766Speter break; 374766Speter default: 375766Speter ap = rvalue( argv[1] , filetype , LREQ ); 376766Speter break; 377766Speter } 378766Speter if (ap == NIL) 379766Speter continue; 380766Speter if (incompat(ap, filetype, argv[1])) { 381766Speter cerror("Type mismatch in write to non-text file"); 382766Speter continue; 383766Speter } 384766Speter switch ( classify( filetype ) ) { 385766Speter case TBOOL: 386766Speter case TCHAR: 387766Speter case TINT: 388766Speter case TSCAL: 389*10373Speter postcheck(filetype, ap); 390*10373Speter sconv(p2type(ap), p2type(filetype)); 391766Speter /* and fall through */ 392766Speter case TDOUBLE: 393766Speter case TPTR: 394766Speter putop( P2ASSIGN , p2type( filetype ) ); 395766Speter putdot( filename , line ); 396766Speter break; 397766Speter default: 398766Speter putstrop( P2STASG 399766Speter , p2type( filetype ) 400766Speter , lwidth( filetype ) 401766Speter , align( filetype ) ); 402766Speter putdot( filename , line ); 403766Speter break; 404766Speter } 405766Speter /* 406766Speter * put(file) 407766Speter */ 408766Speter putleaf( P2ICON , 0 , 0 409766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 410766Speter , "_PUT" ); 4113833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 4123833Speter P2PTR|P2STRTY ); 413766Speter putop( P2CALL , P2INT ); 414766Speter putdot( filename , line ); 415766Speter continue; 416766Speter } 417766Speter /* 418766Speter * Write to a textfile 419766Speter * 420766Speter * Evaluate the expression 421766Speter * to be written. 422766Speter */ 423766Speter if (fmt == 'O' || fmt == 'X') { 424766Speter if (opt('s')) { 425766Speter standard(); 426766Speter error("Oct and hex are non-standard"); 427766Speter } 428766Speter if (typ == TSTR || typ == TDOUBLE) { 429766Speter error("Can't write %ss with oct/hex", clnames[typ]); 430766Speter continue; 431766Speter } 432766Speter if (typ == TCHAR || typ == TBOOL) 433766Speter typ = TINT; 434766Speter } 435766Speter /* 436766Speter * If there is no format specified by the programmer, 437766Speter * implement the default. 438766Speter */ 439766Speter switch (typ) { 4406540Smckusick case TPTR: 4416540Smckusick warning(); 4426540Smckusick if (opt('s')) { 4436540Smckusick standard(); 4446540Smckusick } 4456540Smckusick error("Writing %ss to text files is non-standard", 4466540Smckusick clnames[typ]); 4476540Smckusick /* and fall through */ 448766Speter case TINT: 449766Speter if (fmt == 'f') { 450766Speter typ = TDOUBLE; 451766Speter goto tdouble; 452766Speter } 453766Speter if (fmtspec == NIL) { 454766Speter if (fmt == 'D') 455766Speter field = 10; 456766Speter else if (fmt == 'X') 457766Speter field = 8; 458766Speter else if (fmt == 'O') 459766Speter field = 11; 460766Speter else 461766Speter panic("fmt1"); 462766Speter fmtspec = CONWIDTH; 463766Speter } 464766Speter break; 465766Speter case TCHAR: 466766Speter tchar: 467766Speter fmt = 'c'; 468766Speter break; 469766Speter case TSCAL: 4701629Speter warning(); 471766Speter if (opt('s')) { 472766Speter standard(); 473766Speter } 4746540Smckusick error("Writing %ss to text files is non-standard", 4756540Smckusick clnames[typ]); 476766Speter case TBOOL: 477766Speter fmt = 's'; 478766Speter break; 479766Speter case TDOUBLE: 480766Speter tdouble: 481766Speter switch (fmtspec) { 482766Speter case NIL: 483766Speter field = 21; 484766Speter prec = 14; 4853225Smckusic fmt = 'e'; 486766Speter fmtspec = CONWIDTH + CONPREC; 487766Speter break; 488766Speter case CONWIDTH: 4899229Smckusick field -= REALSPC; 4909229Smckusick if (field < 1) 491766Speter field = 1; 492766Speter prec = field - 7; 493766Speter if (prec < 1) 494766Speter prec = 1; 495766Speter fmtspec += CONPREC; 4963225Smckusic fmt = 'e'; 497766Speter break; 498766Speter case VARWIDTH: 499766Speter fmtspec += VARPREC; 5003225Smckusic fmt = 'e'; 501766Speter break; 502766Speter case CONWIDTH + CONPREC: 503766Speter case CONWIDTH + VARPREC: 5049229Smckusick field -= REALSPC; 5059229Smckusick if (field < 1) 506766Speter field = 1; 507766Speter } 508766Speter format[0] = ' '; 5099229Smckusick fmtstart = 1 - REALSPC; 510766Speter break; 511766Speter case TSTR: 512766Speter constval( alv ); 513766Speter switch ( classify( con.ctype ) ) { 514766Speter case TCHAR: 515766Speter typ = TCHAR; 516766Speter goto tchar; 517766Speter case TSTR: 518766Speter strptr = con.cpval; 519766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 520766Speter strptr = con.cpval; 521766Speter break; 522766Speter default: 523766Speter strnglen = width(ap); 524766Speter break; 525766Speter } 526766Speter fmt = 's'; 527766Speter strfmt = fmtspec; 528766Speter if (fmtspec == NIL) { 529766Speter fmtspec = SKIP; 530766Speter break; 531766Speter } 532766Speter if (fmtspec & CONWIDTH) { 533766Speter if (field <= strnglen) 534766Speter fmtspec = SKIP; 535766Speter else 536766Speter field -= strnglen; 537766Speter } 538766Speter break; 539766Speter default: 540766Speter error("Can't write %ss to a text file", clnames[typ]); 541766Speter continue; 542766Speter } 543766Speter /* 544766Speter * Generate the format string 545766Speter */ 546766Speter switch (fmtspec) { 547766Speter default: 548766Speter panic("fmt2"); 549766Speter case NIL: 550766Speter if (fmt == 'c') { 551766Speter if ( opt( 't' ) ) { 552766Speter putleaf( P2ICON , 0 , 0 553766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 554766Speter , "_WRITEC" ); 5553833Speter putRV( 0 , cbn , CURFILEOFFSET , 5563833Speter NLOCAL , P2PTR|P2STRTY ); 557766Speter stkrval( alv , NIL , RREQ ); 558766Speter putop( P2LISTOP , P2INT ); 559766Speter } else { 560766Speter putleaf( P2ICON , 0 , 0 561766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 562766Speter , "_fputc" ); 563766Speter stkrval( alv , NIL , RREQ ); 564766Speter } 565766Speter putleaf( P2ICON , 0 , 0 566766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 567766Speter , "_ACTFILE" ); 5683833Speter putRV( 0, cbn , CURFILEOFFSET , 5693833Speter NLOCAL , P2PTR|P2STRTY ); 570766Speter putop( P2CALL , P2INT ); 571766Speter putop( P2LISTOP , P2INT ); 572766Speter putop( P2CALL , P2INT ); 573766Speter putdot( filename , line ); 574766Speter } else { 575766Speter sprintf(&format[1], "%%%c", fmt); 576766Speter goto fmtgen; 577766Speter } 578766Speter case SKIP: 579766Speter break; 580766Speter case CONWIDTH: 581766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 582766Speter goto fmtgen; 583766Speter case VARWIDTH: 584766Speter sprintf(&format[1], "%%*%c", fmt); 585766Speter goto fmtgen; 586766Speter case CONWIDTH + CONPREC: 587766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 588766Speter goto fmtgen; 589766Speter case CONWIDTH + VARPREC: 590766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 591766Speter goto fmtgen; 592766Speter case VARWIDTH + CONPREC: 593766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 594766Speter goto fmtgen; 595766Speter case VARWIDTH + VARPREC: 596766Speter sprintf(&format[1], "%%*.*%c", fmt); 597766Speter fmtgen: 598766Speter if ( opt( 't' ) ) { 599766Speter putleaf( P2ICON , 0 , 0 600766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 601766Speter , "_WRITEF" ); 6023833Speter putRV( 0 , cbn , CURFILEOFFSET , 6033833Speter NLOCAL , P2PTR|P2STRTY ); 604766Speter putleaf( P2ICON , 0 , 0 605766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 606766Speter , "_ACTFILE" ); 6073833Speter putRV( 0 , cbn , CURFILEOFFSET , 6083833Speter NLOCAL , P2PTR|P2STRTY ); 609766Speter putop( P2CALL , P2INT ); 610766Speter putop( P2LISTOP , P2INT ); 611766Speter } else { 612766Speter putleaf( P2ICON , 0 , 0 613766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 614766Speter , "_fprintf" ); 615766Speter putleaf( P2ICON , 0 , 0 616766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 617766Speter , "_ACTFILE" ); 6183833Speter putRV( 0 , cbn , CURFILEOFFSET , 6193833Speter NLOCAL , P2PTR|P2STRTY ); 620766Speter putop( P2CALL , P2INT ); 621766Speter } 622766Speter putCONG( &format[ fmtstart ] 623766Speter , strlen( &format[ fmtstart ] ) 624766Speter , LREQ ); 625766Speter putop( P2LISTOP , P2INT ); 626766Speter if ( fmtspec & VARWIDTH ) { 627766Speter /* 628766Speter * either 629766Speter * ,(temp=width,MAX(temp,...)), 630766Speter * or 631766Speter * , MAX( width , ... ) , 632766Speter */ 633766Speter if ( ( typ == TDOUBLE && al[3] == NIL ) 634766Speter || typ == TSTR ) { 6353225Smckusic soffset = sizes[cbn].curtmps; 6363833Speter tempnlp = tmpalloc(sizeof(long), 6373225Smckusic nl+T4INT, REGOK); 6383833Speter putRV( 0 , cbn , 6393833Speter tempnlp -> value[ NL_OFFS ] , 6403833Speter tempnlp -> extra_flags , P2INT ); 641766Speter ap = stkrval( al[2] , NIL , RREQ ); 642766Speter putop( P2ASSIGN , P2INT ); 643766Speter putleaf( P2ICON , 0 , 0 644766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 645766Speter , "_MAX" ); 6463833Speter putRV( 0 , cbn , 6473833Speter tempnlp -> value[ NL_OFFS ] , 6483833Speter tempnlp -> extra_flags , P2INT ); 649766Speter } else { 650766Speter if (opt('t') 651766Speter || typ == TSTR || typ == TDOUBLE) { 652766Speter putleaf( P2ICON , 0 , 0 653766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 654766Speter ,"_MAX" ); 655766Speter } 656766Speter ap = stkrval( al[2] , NIL , RREQ ); 657766Speter } 658766Speter if (ap == NIL) 659766Speter continue; 660766Speter if (isnta(ap,"i")) { 661766Speter error("First write width must be integer, not %s", nameof(ap)); 662766Speter continue; 663766Speter } 664766Speter switch ( typ ) { 665766Speter case TDOUBLE: 6669229Smckusick putleaf( P2ICON , REALSPC , 0 , P2INT , 0 ); 667766Speter putop( P2LISTOP , P2INT ); 668766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 669766Speter putop( P2LISTOP , P2INT ); 670766Speter putop( P2CALL , P2INT ); 671766Speter if ( al[3] == NIL ) { 672766Speter /* 673766Speter * finish up the comma op 674766Speter */ 675766Speter putop( P2COMOP , P2INT ); 676766Speter fmtspec &= ~VARPREC; 677766Speter putop( P2LISTOP , P2INT ); 678766Speter putleaf( P2ICON , 0 , 0 679766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 680766Speter , "_MAX" ); 6813833Speter putRV( 0 , cbn , 6823833Speter tempnlp -> value[ NL_OFFS ] , 6833833Speter tempnlp -> extra_flags , 6843833Speter P2INT ); 6853225Smckusic tmpfree(&soffset); 6869229Smckusick putleaf( P2ICON , 7 + REALSPC , 0 , P2INT , 0 ); 687766Speter putop( P2LISTOP , P2INT ); 688766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 689766Speter putop( P2LISTOP , P2INT ); 690766Speter putop( P2CALL , P2INT ); 691766Speter } 692766Speter putop( P2LISTOP , P2INT ); 693766Speter break; 694766Speter case TSTR: 695766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 696766Speter putop( P2LISTOP , P2INT ); 697766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 698766Speter putop( P2LISTOP , P2INT ); 699766Speter putop( P2CALL , P2INT ); 700766Speter putop( P2COMOP , P2INT ); 701766Speter putop( P2LISTOP , P2INT ); 702766Speter break; 703766Speter default: 704766Speter if (opt('t')) { 705766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 706766Speter putop( P2LISTOP , P2INT ); 707766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 708766Speter putop( P2LISTOP , P2INT ); 709766Speter putop( P2CALL , P2INT ); 710766Speter } 711766Speter putop( P2LISTOP , P2INT ); 712766Speter break; 713766Speter } 714766Speter } 715766Speter /* 716766Speter * If there is a variable precision, 717766Speter * evaluate it 718766Speter */ 719766Speter if (fmtspec & VARPREC) { 720766Speter if (opt('t')) { 721766Speter putleaf( P2ICON , 0 , 0 722766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 723766Speter , "_MAX" ); 724766Speter } 725766Speter ap = stkrval( al[3] , NIL , RREQ ); 726766Speter if (ap == NIL) 727766Speter continue; 728766Speter if (isnta(ap,"i")) { 729766Speter error("Second write width must be integer, not %s", nameof(ap)); 730766Speter continue; 731766Speter } 732766Speter if (opt('t')) { 733766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 734766Speter putop( P2LISTOP , P2INT ); 735766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 736766Speter putop( P2LISTOP , P2INT ); 737766Speter putop( P2CALL , P2INT ); 738766Speter } 739766Speter putop( P2LISTOP , P2INT ); 740766Speter } 741766Speter /* 742766Speter * evaluate the thing we want printed. 743766Speter */ 744766Speter switch ( typ ) { 7456540Smckusick case TPTR: 746766Speter case TCHAR: 747766Speter case TINT: 748766Speter stkrval( alv , NIL , RREQ ); 749766Speter putop( P2LISTOP , P2INT ); 750766Speter break; 751766Speter case TDOUBLE: 752766Speter ap = stkrval( alv , NIL , RREQ ); 753*10373Speter if (isnta(ap, "d")) { 754*10373Speter sconv(p2type(ap), P2DOUBLE); 755766Speter } 756766Speter putop( P2LISTOP , P2INT ); 757766Speter break; 758766Speter case TSCAL: 759766Speter case TBOOL: 760766Speter putleaf( P2ICON , 0 , 0 761766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 762766Speter , "_NAM" ); 763766Speter ap = stkrval( alv , NIL , RREQ ); 764766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 765766Speter , listnames( ap ) ); 766766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 767766Speter , format ); 768766Speter putop( P2LISTOP , P2INT ); 769766Speter putop( P2CALL , P2INT ); 770766Speter putop( P2LISTOP , P2INT ); 771766Speter break; 772766Speter case TSTR: 773766Speter putCONG( "" , 0 , LREQ ); 774766Speter putop( P2LISTOP , P2INT ); 775766Speter break; 7766540Smckusick default: 7776540Smckusick panic("fmt3"); 7786540Smckusick break; 779766Speter } 780766Speter putop( P2CALL , P2INT ); 781766Speter putdot( filename , line ); 782766Speter } 783766Speter /* 784766Speter * Write the string after its blank padding 785766Speter */ 786766Speter if (typ == TSTR ) { 787766Speter if ( opt( 't' ) ) { 788766Speter putleaf( P2ICON , 0 , 0 789766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 790766Speter , "_WRITES" ); 7913833Speter putRV( 0 , cbn , CURFILEOFFSET , 7923833Speter NLOCAL , P2PTR|P2STRTY ); 793766Speter ap = stkrval(alv, NIL , RREQ ); 794766Speter putop( P2LISTOP , P2INT ); 795766Speter } else { 796766Speter putleaf( P2ICON , 0 , 0 797766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 798766Speter , "_fwrite" ); 799766Speter ap = stkrval(alv, NIL , RREQ ); 800766Speter } 801766Speter if (strfmt & VARWIDTH) { 802766Speter /* 803766Speter * min, inline expanded as 804766Speter * temp < len ? temp : len 805766Speter */ 8063833Speter putRV( 0 , cbn , 8073833Speter tempnlp -> value[ NL_OFFS ] , 8083833Speter tempnlp -> extra_flags , P2INT ); 809766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 810766Speter putop( P2LT , P2INT ); 8113833Speter putRV( 0 , cbn , 8123833Speter tempnlp -> value[ NL_OFFS ] , 8133833Speter tempnlp -> extra_flags , P2INT ); 814766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 815766Speter putop( P2COLON , P2INT ); 816766Speter putop( P2QUEST , P2INT ); 8173225Smckusic tmpfree(&soffset); 818766Speter } else { 819766Speter if ( ( fmtspec & SKIP ) 820766Speter && ( strfmt & CONWIDTH ) ) { 821766Speter strnglen = field; 822766Speter } 823766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 824766Speter } 825766Speter putop( P2LISTOP , P2INT ); 826766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 827766Speter putop( P2LISTOP , P2INT ); 828766Speter putleaf( P2ICON , 0 , 0 829766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 830766Speter , "_ACTFILE" ); 8313833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 8323833Speter P2PTR|P2STRTY ); 833766Speter putop( P2CALL , P2INT ); 834766Speter putop( P2LISTOP , P2INT ); 835766Speter putop( P2CALL , P2INT ); 836766Speter putdot( filename , line ); 837766Speter } 838766Speter } 839766Speter /* 840766Speter * Done with arguments. 841766Speter * Handle writeln and 842766Speter * insufficent number of args. 843766Speter */ 844766Speter switch (p->value[0] &~ NSTAND) { 845766Speter case O_WRITEF: 846766Speter if (argc == 0) 847766Speter error("Write requires an argument"); 848766Speter break; 849766Speter case O_MESSAGE: 850766Speter if (argc == 0) 851766Speter error("Message requires an argument"); 852766Speter case O_WRITLN: 853766Speter if (filetype != nl+T1CHAR) 854766Speter error("Can't 'writeln' a non text file"); 855766Speter if ( opt( 't' ) ) { 856766Speter putleaf( P2ICON , 0 , 0 857766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 858766Speter , "_WRITLN" ); 8593833Speter putRV( 0 , cbn , CURFILEOFFSET , 8603833Speter NLOCAL , P2PTR|P2STRTY ); 861766Speter } else { 862766Speter putleaf( P2ICON , 0 , 0 863766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 864766Speter , "_fputc" ); 865766Speter putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 ); 866766Speter putleaf( P2ICON , 0 , 0 867766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 868766Speter , "_ACTFILE" ); 8693833Speter putRV( 0 , cbn , CURFILEOFFSET , 8703833Speter NLOCAL , P2PTR|P2STRTY ); 871766Speter putop( P2CALL , P2INT ); 872766Speter putop( P2LISTOP , P2INT ); 873766Speter } 874766Speter putop( P2CALL , P2INT ); 875766Speter putdot( filename , line ); 876766Speter break; 877766Speter } 878766Speter return; 879766Speter 880766Speter case O_READ4: 881766Speter case O_READLN: 882766Speter /* 883766Speter * Set up default 884766Speter * file "input". 885766Speter */ 886766Speter file = NIL; 887766Speter filetype = nl+T1CHAR; 888766Speter /* 889766Speter * Determine the file implied 890766Speter * for the read and generate 891766Speter * code to make it the active file. 892766Speter */ 893766Speter if (argv != NIL) { 894766Speter codeoff(); 895766Speter ap = stkrval(argv[1], NIL , RREQ ); 896766Speter codeon(); 897766Speter if (ap == NIL) 898766Speter argv = argv[2]; 899766Speter if (ap != NIL && ap->class == FILET) { 900766Speter /* 901766Speter * Got "read(f, ...", make 902766Speter * f the active file, and save 903766Speter * it and its type for use in 904766Speter * processing the rest of the 905766Speter * arguments to read. 906766Speter */ 907766Speter file = argv[1]; 908766Speter filetype = ap->type; 9093833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9103833Speter P2PTR|P2STRTY ); 911766Speter putleaf( P2ICON , 0 , 0 912766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 913766Speter , "_UNIT" ); 914766Speter stklval(argv[1], NOFLAGS); 915766Speter putop( P2CALL , P2INT ); 916766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 917766Speter putdot( filename , line ); 918766Speter argv = argv[2]; 919766Speter argc--; 920766Speter } else { 921766Speter /* 922766Speter * Default is read from 923766Speter * standard input. 924766Speter */ 9253833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9263833Speter P2PTR|P2STRTY ); 9273833Speter putLV( "_input" , 0 , 0 , NGLOBAL , 9283833Speter P2PTR|P2STRTY ); 929766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 930766Speter putdot( filename , line ); 931766Speter input->nl_flags |= NUSED; 932766Speter } 933766Speter } else { 9343833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9353833Speter P2PTR|P2STRTY ); 9363833Speter putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 937766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 938766Speter putdot( filename , line ); 939766Speter input->nl_flags |= NUSED; 940766Speter } 941766Speter /* 942766Speter * Loop and process each 943766Speter * of the arguments. 944766Speter */ 945766Speter for (; argv != NIL; argv = argv[2]) { 946766Speter /* 947766Speter * Get the address of the target 948766Speter * on the stack. 949766Speter */ 950766Speter al = argv[1]; 951766Speter if (al == NIL) 952766Speter continue; 953766Speter if (al[0] != T_VAR) { 954766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 955766Speter continue; 956766Speter } 957766Speter codeoff(); 958766Speter ap = stklval(al, MOD|ASGN|NOUSE); 959766Speter codeon(); 960766Speter if (ap == NIL) 961766Speter continue; 962766Speter if (filetype != nl+T1CHAR) { 963766Speter /* 964766Speter * Generalized read, i.e. 965766Speter * from a non-textfile. 966766Speter */ 967766Speter if (incompat(filetype, ap, argv[1] )) { 968766Speter error("Type mismatch in read from non-text file"); 969766Speter continue; 970766Speter } 971766Speter /* 972766Speter * var := file ^; 973766Speter */ 974766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 975766Speter if ( isa( ap , "bsci" ) ) { 976766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 977766Speter } 978766Speter putleaf( P2ICON , 0 , 0 979766Speter , ADDTYPE( 980766Speter ADDTYPE( 981766Speter ADDTYPE( 982766Speter p2type( filetype ) , P2PTR ) 983766Speter , P2FTN ) 984766Speter , P2PTR ) 985766Speter , "_FNIL" ); 986766Speter if (file != NIL) 987766Speter stklval(file, NOFLAGS); 988766Speter else /* Magic */ 9893833Speter putRV( "_input" , 0 , 0 , NGLOBAL , 9903833Speter P2PTR | P2STRTY ); 991766Speter putop( P2CALL , P2INT ); 992766Speter switch ( classify( filetype ) ) { 993766Speter case TBOOL: 994766Speter case TCHAR: 995766Speter case TINT: 996766Speter case TSCAL: 997766Speter case TDOUBLE: 998766Speter case TPTR: 999766Speter putop( P2UNARY P2MUL 1000766Speter , p2type( filetype ) ); 1001766Speter } 1002766Speter switch ( classify( filetype ) ) { 1003766Speter case TBOOL: 1004766Speter case TCHAR: 1005766Speter case TINT: 1006766Speter case TSCAL: 1007*10373Speter postcheck(ap, filetype); 1008*10373Speter sconv(p2type(filetype), p2type(ap)); 1009766Speter /* and fall through */ 1010766Speter case TDOUBLE: 1011766Speter case TPTR: 1012766Speter putop( P2ASSIGN , p2type( ap ) ); 1013766Speter putdot( filename , line ); 1014766Speter break; 1015766Speter default: 1016766Speter putstrop( P2STASG 1017766Speter , p2type( ap ) 1018766Speter , lwidth( ap ) 1019766Speter , align( ap ) ); 1020766Speter putdot( filename , line ); 1021766Speter break; 1022766Speter } 1023766Speter /* 1024766Speter * get(file); 1025766Speter */ 1026766Speter putleaf( P2ICON , 0 , 0 1027766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1028766Speter , "_GET" ); 10293833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10303833Speter P2PTR|P2STRTY ); 1031766Speter putop( P2CALL , P2INT ); 1032766Speter putdot( filename , line ); 1033766Speter continue; 1034766Speter } 1035766Speter /* 1036766Speter * if you get to here, you are reading from 1037766Speter * a text file. only possiblities are: 1038766Speter * character, integer, real, or scalar. 1039766Speter * read( f , foo , ... ) is done as 1040766Speter * foo := read( f ) with rangechecking 1041766Speter * if appropriate. 1042766Speter */ 1043766Speter typ = classify(ap); 1044766Speter op = rdops(typ); 1045766Speter if (op == NIL) { 1046766Speter error("Can't read %ss from a text file", clnames[typ]); 1047766Speter continue; 1048766Speter } 1049766Speter /* 1050766Speter * left hand side of foo := read( f ) 1051766Speter */ 1052766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 1053766Speter if ( isa( ap , "bsci" ) ) { 1054766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1055766Speter } 1056766Speter switch ( op ) { 1057766Speter case O_READC: 1058766Speter readname = "_READC"; 1059766Speter readtype = P2INT; 1060766Speter break; 1061766Speter case O_READ4: 1062766Speter readname = "_READ4"; 1063766Speter readtype = P2INT; 1064766Speter break; 1065766Speter case O_READ8: 1066766Speter readname = "_READ8"; 1067766Speter readtype = P2DOUBLE; 1068766Speter break; 1069766Speter case O_READE: 1070766Speter readname = "_READE"; 1071766Speter readtype = P2INT; 1072766Speter break; 1073766Speter } 1074766Speter putleaf( P2ICON , 0 , 0 1075766Speter , ADDTYPE( P2FTN | readtype , P2PTR ) 1076766Speter , readname ); 10773833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10783833Speter P2PTR|P2STRTY ); 1079766Speter if ( op == O_READE ) { 1080766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1081766Speter , listnames( ap ) ); 1082766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 1083766Speter , format ); 1084766Speter putop( P2LISTOP , P2INT ); 10851629Speter warning(); 1086766Speter if (opt('s')) { 1087766Speter standard(); 1088766Speter } 10891629Speter error("Reading scalars from text files is non-standard"); 1090766Speter } 1091766Speter putop( P2CALL , readtype ); 1092766Speter if ( isa( ap , "bcsi" ) ) { 1093*10373Speter postcheck(ap, readtype==P2INT?nl+T4INT:nl+TDOUBLE); 1094766Speter } 1095*10373Speter sconv(readtype, p2type(ap)); 1096766Speter putop( P2ASSIGN , p2type( ap ) ); 1097766Speter putdot( filename , line ); 1098766Speter } 1099766Speter /* 1100766Speter * Done with arguments. 1101766Speter * Handle readln and 1102766Speter * insufficient number of args. 1103766Speter */ 1104766Speter if (p->value[0] == O_READLN) { 1105766Speter if (filetype != nl+T1CHAR) 1106766Speter error("Can't 'readln' a non text file"); 1107766Speter putleaf( P2ICON , 0 , 0 1108766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1109766Speter , "_READLN" ); 11103833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 11113833Speter P2PTR|P2STRTY ); 1112766Speter putop( P2CALL , P2INT ); 1113766Speter putdot( filename , line ); 1114766Speter } else if (argc == 0) 1115766Speter error("read requires an argument"); 1116766Speter return; 1117766Speter 1118766Speter case O_GET: 1119766Speter case O_PUT: 1120766Speter if (argc != 1) { 1121766Speter error("%s expects one argument", p->symbol); 1122766Speter return; 1123766Speter } 11243833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1125766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1126766Speter , "_UNIT" ); 1127766Speter ap = stklval(argv[1], NOFLAGS); 1128766Speter if (ap == NIL) 1129766Speter return; 1130766Speter if (ap->class != FILET) { 1131766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1132766Speter return; 1133766Speter } 1134766Speter putop( P2CALL , P2INT ); 1135766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1136766Speter putdot( filename , line ); 1137766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1138766Speter , op == O_GET ? "_GET" : "_PUT" ); 11393833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1140766Speter putop( P2CALL , P2INT ); 1141766Speter putdot( filename , line ); 1142766Speter return; 1143766Speter 1144766Speter case O_RESET: 1145766Speter case O_REWRITE: 1146766Speter if (argc == 0 || argc > 2) { 1147766Speter error("%s expects one or two arguments", p->symbol); 1148766Speter return; 1149766Speter } 1150766Speter if (opt('s') && argc == 2) { 1151766Speter standard(); 1152766Speter error("Two argument forms of reset and rewrite are non-standard"); 1153766Speter } 1154766Speter putleaf( P2ICON , 0 , 0 , P2INT 1155766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 1156766Speter ap = stklval(argv[1], MOD|NOUSE); 1157766Speter if (ap == NIL) 1158766Speter return; 1159766Speter if (ap->class != FILET) { 1160766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1161766Speter return; 1162766Speter } 1163766Speter if (argc == 2) { 1164766Speter /* 1165766Speter * Optional second argument 1166766Speter * is a string name of a 1167766Speter * UNIX (R) file to be associated. 1168766Speter */ 1169766Speter al = argv[2]; 1170766Speter al = stkrval(al[1], NOFLAGS , RREQ ); 1171766Speter if (al == NIL) 1172766Speter return; 1173766Speter if (classify(al) != TSTR) { 1174766Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 1175766Speter return; 1176766Speter } 1177766Speter strnglen = width(al); 1178766Speter } else { 1179766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 1180766Speter strnglen = 0; 1181766Speter } 1182766Speter putop( P2LISTOP , P2INT ); 1183766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 1184766Speter putop( P2LISTOP , P2INT ); 1185766Speter putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 ); 1186766Speter putop( P2LISTOP , P2INT ); 1187766Speter putop( P2CALL , P2INT ); 1188766Speter putdot( filename , line ); 1189766Speter return; 1190766Speter 1191766Speter case O_NEW: 1192766Speter case O_DISPOSE: 1193766Speter if (argc == 0) { 1194766Speter error("%s expects at least one argument", p->symbol); 1195766Speter return; 1196766Speter } 11979139Smckusick alv = argv[1]; 11987967Smckusick codeoff(); 11999139Smckusick ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 12007967Smckusick codeon(); 1201766Speter if (ap == NIL) 1202766Speter return; 1203766Speter if (ap->class != PTR) { 1204766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1205766Speter return; 1206766Speter } 1207766Speter ap = ap->type; 1208766Speter if (ap == NIL) 1209766Speter return; 12109139Smckusick if (op == O_NEW) 12119139Smckusick cmd = "_NEW"; 12129139Smckusick else /* op == O_DISPOSE */ 12137967Smckusick if ((ap->nl_flags & NFILES) != 0) 12147967Smckusick cmd = "_DFDISPOSE"; 12157967Smckusick else 12167967Smckusick cmd = "_DISPOSE"; 12177967Smckusick putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd); 12189139Smckusick stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1219766Speter argv = argv[2]; 1220766Speter if (argv != NIL) { 1221766Speter if (ap->class != RECORD) { 1222766Speter error("Record required when specifying variant tags"); 1223766Speter return; 1224766Speter } 1225766Speter for (; argv != NIL; argv = argv[2]) { 1226766Speter if (ap->ptr[NL_VARNT] == NIL) { 1227766Speter error("Too many tag fields"); 1228766Speter return; 1229766Speter } 1230766Speter if (!isconst(argv[1])) { 1231766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1232766Speter return; 1233766Speter } 1234766Speter gconst(argv[1]); 1235766Speter if (con.ctype == NIL) 1236766Speter return; 1237766Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 1238766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1239766Speter return; 1240766Speter } 1241766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1242766Speter if (ap->range[0] == con.crval) 1243766Speter break; 1244766Speter if (ap == NIL) { 1245766Speter error("No variant case label value equals specified constant value"); 1246766Speter return; 1247766Speter } 1248766Speter ap = ap->ptr[NL_VTOREC]; 1249766Speter } 1250766Speter } 1251766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1252766Speter putop( P2LISTOP , P2INT ); 1253766Speter putop( P2CALL , P2INT ); 1254766Speter putdot( filename , line ); 12559139Smckusick if (opt('t') && op == O_NEW) { 12569139Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 12579139Smckusick , "_blkclr" ); 12589264Smckusick stkrval(alv, NIL , RREQ ); 12599139Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 12609139Smckusick putop( P2LISTOP , P2INT ); 12619139Smckusick putop( P2CALL , P2INT ); 12629139Smckusick putdot( filename , line ); 12639139Smckusick } 1264766Speter return; 1265766Speter 1266766Speter case O_DATE: 1267766Speter case O_TIME: 1268766Speter if (argc != 1) { 1269766Speter error("%s expects one argument", p->symbol); 1270766Speter return; 1271766Speter } 1272766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1273766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 1274766Speter ap = stklval(argv[1], MOD|NOUSE); 1275766Speter if (ap == NIL) 1276766Speter return; 1277766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1278766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1279766Speter return; 1280766Speter } 1281766Speter putop( P2CALL , P2INT ); 1282766Speter putdot( filename , line ); 1283766Speter return; 1284766Speter 1285766Speter case O_HALT: 1286766Speter if (argc != 0) { 1287766Speter error("halt takes no arguments"); 1288766Speter return; 1289766Speter } 1290766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1291766Speter , "_HALT" ); 1292766Speter 1293766Speter putop( P2UNARY P2CALL , P2INT ); 1294766Speter putdot( filename , line ); 1295766Speter noreach = 1; 1296766Speter return; 1297766Speter 1298766Speter case O_ARGV: 1299766Speter if (argc != 2) { 1300766Speter error("argv takes two arguments"); 1301766Speter return; 1302766Speter } 1303766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1304766Speter , "_ARGV" ); 1305766Speter ap = stkrval(argv[1], NIL , RREQ ); 1306766Speter if (ap == NIL) 1307766Speter return; 1308766Speter if (isnta(ap, "i")) { 1309766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1310766Speter return; 1311766Speter } 1312766Speter al = argv[2]; 1313766Speter ap = stklval(al[1], MOD|NOUSE); 1314766Speter if (ap == NIL) 1315766Speter return; 1316766Speter if (classify(ap) != TSTR) { 1317766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1318766Speter return; 1319766Speter } 1320766Speter putop( P2LISTOP , P2INT ); 1321766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1322766Speter putop( P2LISTOP , P2INT ); 1323766Speter putop( P2CALL , P2INT ); 1324766Speter putdot( filename , line ); 1325766Speter return; 1326766Speter 1327766Speter case O_STLIM: 1328766Speter if (argc != 1) { 1329766Speter error("stlimit requires one argument"); 1330766Speter return; 1331766Speter } 1332766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1333766Speter , "_STLIM" ); 1334766Speter ap = stkrval(argv[1], NIL , RREQ ); 1335766Speter if (ap == NIL) 1336766Speter return; 1337766Speter if (isnta(ap, "i")) { 1338766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1339766Speter return; 1340766Speter } 1341766Speter putop( P2CALL , P2INT ); 1342766Speter putdot( filename , line ); 1343766Speter return; 1344766Speter 1345766Speter case O_REMOVE: 1346766Speter if (argc != 1) { 1347766Speter error("remove expects one argument"); 1348766Speter return; 1349766Speter } 1350766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1351766Speter , "_REMOVE" ); 1352766Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 1353766Speter if (ap == NIL) 1354766Speter return; 1355766Speter if (classify(ap) != TSTR) { 1356766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1357766Speter return; 1358766Speter } 1359766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1360766Speter putop( P2LISTOP , P2INT ); 1361766Speter putop( P2CALL , P2INT ); 1362766Speter putdot( filename , line ); 1363766Speter return; 1364766Speter 1365766Speter case O_LLIMIT: 1366766Speter if (argc != 2) { 1367766Speter error("linelimit expects two arguments"); 1368766Speter return; 1369766Speter } 1370766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1371766Speter , "_LLIMIT" ); 1372766Speter ap = stklval(argv[1], NOFLAGS|NOUSE); 1373766Speter if (ap == NIL) 1374766Speter return; 1375766Speter if (!text(ap)) { 1376766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1377766Speter return; 1378766Speter } 1379766Speter al = argv[2]; 1380766Speter ap = stkrval(al[1], NIL , RREQ ); 1381766Speter if (ap == NIL) 1382766Speter return; 1383766Speter if (isnta(ap, "i")) { 1384766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1385766Speter return; 1386766Speter } 1387766Speter putop( P2LISTOP , P2INT ); 1388766Speter putop( P2CALL , P2INT ); 1389766Speter putdot( filename , line ); 1390766Speter return; 1391766Speter case O_PAGE: 1392766Speter if (argc != 1) { 1393766Speter error("page expects one argument"); 1394766Speter return; 1395766Speter } 13963833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1397766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1398766Speter , "_UNIT" ); 1399766Speter ap = stklval(argv[1], NOFLAGS); 1400766Speter if (ap == NIL) 1401766Speter return; 1402766Speter if (!text(ap)) { 1403766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1404766Speter return; 1405766Speter } 1406766Speter putop( P2CALL , P2INT ); 1407766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1408766Speter putdot( filename , line ); 1409766Speter if ( opt( 't' ) ) { 1410766Speter putleaf( P2ICON , 0 , 0 1411766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1412766Speter , "_PAGE" ); 14133833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1414766Speter } else { 1415766Speter putleaf( P2ICON , 0 , 0 1416766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1417766Speter , "_fputc" ); 1418766Speter putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 ); 1419766Speter putleaf( P2ICON , 0 , 0 1420766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1421766Speter , "_ACTFILE" ); 14223833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1423766Speter putop( P2CALL , P2INT ); 1424766Speter putop( P2LISTOP , P2INT ); 1425766Speter } 1426766Speter putop( P2CALL , P2INT ); 1427766Speter putdot( filename , line ); 1428766Speter return; 1429766Speter 14307928Smckusick case O_ASRT: 14317928Smckusick if (!opt('t')) 14327928Smckusick return; 14337928Smckusick if (argc == 0 || argc > 2) { 14347928Smckusick error("Assert expects one or two arguments"); 14357928Smckusick return; 14367928Smckusick } 14379139Smckusick if (argc == 2) 14389139Smckusick cmd = "_ASRTS"; 14399139Smckusick else 14409139Smckusick cmd = "_ASRT"; 14417928Smckusick putleaf( P2ICON , 0 , 0 14429139Smckusick , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd ); 14437928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 14447928Smckusick if (ap == NIL) 14457928Smckusick return; 14467928Smckusick if (isnta(ap, "b")) 14477928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 14487928Smckusick if (argc == 2) { 14497928Smckusick /* 14507928Smckusick * Optional second argument is a string specifying 14517928Smckusick * why the assertion failed. 14527928Smckusick */ 14537928Smckusick al = argv[2]; 14547928Smckusick al = stkrval(al[1], NIL , RREQ ); 14557928Smckusick if (al == NIL) 14567928Smckusick return; 14577928Smckusick if (classify(al) != TSTR) { 14587928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 14597928Smckusick return; 14607928Smckusick } 14619139Smckusick putop( P2LISTOP , P2INT ); 14627928Smckusick } 14637928Smckusick putop( P2CALL , P2INT ); 14647928Smckusick putdot( filename , line ); 14657928Smckusick return; 14667928Smckusick 1467766Speter case O_PACK: 1468766Speter if (argc != 3) { 1469766Speter error("pack expects three arguments"); 1470766Speter return; 1471766Speter } 1472766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1473766Speter , "_PACK" ); 1474766Speter pu = "pack(a,i,z)"; 1475766Speter pua = (al = argv)[1]; 1476766Speter pui = (al = al[2])[1]; 1477766Speter puz = (al = al[2])[1]; 1478766Speter goto packunp; 1479766Speter case O_UNPACK: 1480766Speter if (argc != 3) { 1481766Speter error("unpack expects three arguments"); 1482766Speter return; 1483766Speter } 1484766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1485766Speter , "_UNPACK" ); 1486766Speter pu = "unpack(z,a,i)"; 1487766Speter puz = (al = argv)[1]; 1488766Speter pua = (al = al[2])[1]; 1489766Speter pui = (al = al[2])[1]; 1490766Speter packunp: 1491766Speter ap = stkrval((int *) pui, NLNIL , RREQ ); 1492766Speter if (ap == NIL) 1493766Speter return; 1494766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1495766Speter if (ap == NIL) 1496766Speter return; 1497766Speter if (ap->class != ARRAY) { 1498766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1499766Speter return; 1500766Speter } 1501766Speter putop( P2LISTOP , P2INT ); 1502766Speter al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1503766Speter if (al->class != ARRAY) { 1504766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1505766Speter return; 1506766Speter } 1507766Speter if (al->type == NIL || ap->type == NIL) 1508766Speter return; 1509766Speter if (al->type != ap->type) { 1510766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1511766Speter return; 1512766Speter } 1513766Speter putop( P2LISTOP , P2INT ); 1514766Speter k = width(al); 1515766Speter itemwidth = width(ap->type); 1516766Speter ap = ap->chain; 1517766Speter al = al->chain; 1518766Speter if (ap->chain != NIL || al->chain != NIL) { 1519766Speter error("%s requires a and z to be single dimension arrays", pu); 1520766Speter return; 1521766Speter } 1522766Speter if (ap == NIL || al == NIL) 1523766Speter return; 1524766Speter /* 1525766Speter * al is the range for z i.e. u..v 1526766Speter * ap is the range for a i.e. m..n 1527766Speter * i will be n-m+1 1528766Speter * j will be v-u+1 1529766Speter */ 1530766Speter i = ap->range[1] - ap->range[0] + 1; 1531766Speter j = al->range[1] - al->range[0] + 1; 1532766Speter if (i < j) { 1533766Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1534766Speter return; 1535766Speter } 1536766Speter /* 1537766Speter * get n-m-(v-u) and m for the interpreter 1538766Speter */ 1539766Speter i -= j; 1540766Speter j = ap->range[0]; 1541766Speter putleaf( P2ICON , itemwidth , 0 , P2INT , 0 ); 1542766Speter putop( P2LISTOP , P2INT ); 1543766Speter putleaf( P2ICON , j , 0 , P2INT , 0 ); 1544766Speter putop( P2LISTOP , P2INT ); 1545766Speter putleaf( P2ICON , i , 0 , P2INT , 0 ); 1546766Speter putop( P2LISTOP , P2INT ); 1547766Speter putleaf( P2ICON , k , 0 , P2INT , 0 ); 1548766Speter putop( P2LISTOP , P2INT ); 1549766Speter putop( P2CALL , P2INT ); 1550766Speter putdot( filename , line ); 1551766Speter return; 1552766Speter case 0: 15537928Smckusick error("%s is an unimplemented extension", p->symbol); 1554766Speter return; 1555766Speter 1556766Speter default: 1557766Speter panic("proc case"); 1558766Speter } 1559766Speter } 1560766Speter #endif PC 1561