1766Speter /* Copyright (c) 1979 Regents of the University of California */ 2766Speter 3*9139Smckusick static char sccsid[] = "@(#)pcproc.c 1.13 11/12/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 /* 17766Speter * The following array is used to determine which classes may be read 18766Speter * from textfiles. It is indexed by the return value from classify. 19766Speter */ 20766Speter #define rdops(x) rdxxxx[(x)-(TFIRST)] 21766Speter 22766Speter int rdxxxx[] = { 23766Speter 0, /* -7 file types */ 24766Speter 0, /* -6 record types */ 25766Speter 0, /* -5 array types */ 26766Speter O_READE, /* -4 scalar types */ 27766Speter 0, /* -3 pointer types */ 28766Speter 0, /* -2 set types */ 29766Speter 0, /* -1 string types */ 30766Speter 0, /* 0 nil, no type */ 31766Speter O_READE, /* 1 boolean */ 32766Speter O_READC, /* 2 character */ 33766Speter O_READ4, /* 3 integer */ 34766Speter O_READ8 /* 4 real */ 35766Speter }; 36766Speter 37766Speter /* 38766Speter * Proc handles procedure calls. 39766Speter * Non-builtin procedures are "buck-passed" to func (with a flag 40766Speter * indicating that they are actually procedures. 41766Speter * builtin procedures are handled here. 42766Speter */ 43766Speter pcproc(r) 44766Speter int *r; 45766Speter { 46766Speter register struct nl *p; 47766Speter register int *alv, *al, op; 48766Speter struct nl *filetype, *ap; 49766Speter int argc, *argv, typ, fmtspec, strfmt, stkcnt, *file; 507967Smckusick char fmt, format[20], *strptr, *cmd; 51766Speter int prec, field, strnglen, fmtlen, fmtstart, pu; 52766Speter int *pua, *pui, *puz; 53766Speter int i, j, k; 54766Speter int itemwidth; 553833Speter char *readname; 563833Speter struct nl *tempnlp; 573833Speter long readtype; 583833Speter struct tmps soffset; 59766Speter 60766Speter #define CONPREC 4 61766Speter #define VARPREC 8 62766Speter #define CONWIDTH 1 63766Speter #define VARWIDTH 2 64766Speter #define SKIP 16 65766Speter 66766Speter /* 67766Speter * Verify that the name is 68766Speter * defined and is that of a 69766Speter * procedure. 70766Speter */ 71766Speter p = lookup(r[2]); 72766Speter if (p == NIL) { 73766Speter rvlist(r[3]); 74766Speter return; 75766Speter } 761197Speter if (p->class != PROC && p->class != FPROC) { 77766Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 78766Speter rvlist(r[3]); 79766Speter return; 80766Speter } 81766Speter argv = r[3]; 82766Speter 83766Speter /* 84766Speter * Call handles user defined 85766Speter * procedures and functions. 86766Speter */ 87766Speter if (bn != 0) { 88766Speter call(p, argv, PROC, bn); 89766Speter return; 90766Speter } 91766Speter 92766Speter /* 93766Speter * Call to built-in procedure. 94766Speter * Count the arguments. 95766Speter */ 96766Speter argc = 0; 97766Speter for (al = argv; al != NIL; al = al[2]) 98766Speter argc++; 99766Speter 100766Speter /* 101766Speter * Switch on the operator 102766Speter * associated with the built-in 103766Speter * procedure in the namelist 104766Speter */ 105766Speter op = p->value[0] &~ NSTAND; 106766Speter if (opt('s') && (p->value[0] & NSTAND)) { 107766Speter standard(); 108766Speter error("%s is a nonstandard procedure", p->symbol); 109766Speter } 110766Speter switch (op) { 111766Speter 112766Speter case O_ABORT: 113766Speter if (argc != 0) 114766Speter error("null takes no arguments"); 115766Speter return; 116766Speter 117766Speter case O_FLUSH: 118766Speter if (argc == 0) { 119766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 120766Speter putop( P2UNARY P2CALL , P2INT ); 121766Speter putdot( filename , line ); 122766Speter return; 123766Speter } 124766Speter if (argc != 1) { 125766Speter error("flush takes at most one argument"); 126766Speter return; 127766Speter } 128766Speter putleaf( P2ICON , 0 , 0 129766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 130766Speter , "_FLUSH" ); 131766Speter ap = stklval(argv[1], NOFLAGS); 132766Speter if (ap == NIL) 133766Speter return; 134766Speter if (ap->class != FILET) { 135766Speter error("flush's argument must be a file, not %s", nameof(ap)); 136766Speter return; 137766Speter } 138766Speter putop( P2CALL , P2INT ); 139766Speter putdot( filename , line ); 140766Speter return; 141766Speter 142766Speter case O_MESSAGE: 143766Speter case O_WRITEF: 144766Speter case O_WRITLN: 145766Speter /* 146766Speter * Set up default file "output"'s type 147766Speter */ 148766Speter file = NIL; 149766Speter filetype = nl+T1CHAR; 150766Speter /* 151766Speter * Determine the file implied 152766Speter * for the write and generate 153766Speter * code to make it the active file. 154766Speter */ 155766Speter if (op == O_MESSAGE) { 156766Speter /* 157766Speter * For message, all that matters 158766Speter * is that the filetype is 159766Speter * a character file. 160766Speter * Thus "output" will suit us fine. 161766Speter */ 162766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 163766Speter putop( P2UNARY P2CALL , P2INT ); 164766Speter putdot( filename , line ); 1653833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 1663833Speter P2PTR|P2STRTY ); 1673833Speter putLV( "__err" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 168766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 169766Speter putdot( filename , line ); 170766Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 171766Speter /* 172766Speter * If there is a first argument which has 173766Speter * no write widths, then it is potentially 174766Speter * a file name. 175766Speter */ 176766Speter codeoff(); 177766Speter ap = stkrval(argv[1], NIL , RREQ ); 178766Speter codeon(); 179766Speter if (ap == NIL) 180766Speter argv = argv[2]; 181766Speter if (ap != NIL && ap->class == FILET) { 182766Speter /* 183766Speter * Got "write(f, ...", make 184766Speter * f the active file, and save 185766Speter * it and its type for use in 186766Speter * processing the rest of the 187766Speter * arguments to write. 188766Speter */ 1893833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 1903833Speter P2PTR|P2STRTY ); 191766Speter putleaf( P2ICON , 0 , 0 192766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 193766Speter , "_UNIT" ); 194766Speter file = argv[1]; 195766Speter filetype = ap->type; 196766Speter stklval(argv[1], NOFLAGS); 197766Speter putop( P2CALL , P2INT ); 198766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 199766Speter putdot( filename , line ); 200766Speter /* 201766Speter * Skip over the first argument 202766Speter */ 203766Speter argv = argv[2]; 204766Speter argc--; 205766Speter } else { 206766Speter /* 207766Speter * Set up for writing on 208766Speter * standard output. 209766Speter */ 2103833Speter putRV( 0, cbn , CURFILEOFFSET , 2113833Speter NLOCAL , P2PTR|P2STRTY ); 2123833Speter putLV( "_output" , 0 , 0 , NGLOBAL , 2133833Speter P2PTR|P2STRTY ); 214766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 215766Speter putdot( filename , line ); 2167954Speter output->nl_flags |= NUSED; 217766Speter } 218766Speter } else { 2193833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 2203833Speter P2PTR|P2STRTY ); 2213833Speter putLV( "_output" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 222766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 223766Speter putdot( filename , line ); 2247954Speter output->nl_flags |= NUSED; 225766Speter } 226766Speter /* 227766Speter * Loop and process each 228766Speter * of the arguments. 229766Speter */ 230766Speter for (; argv != NIL; argv = argv[2]) { 231766Speter /* 232766Speter * fmtspec indicates the type (CONstant or VARiable) 233766Speter * and number (none, WIDTH, and/or PRECision) 234766Speter * of the fields in the printf format for this 235766Speter * output variable. 236766Speter * stkcnt is the number of longs pushed on the stack 237766Speter * fmt is the format output indicator (D, E, F, O, X, S) 238766Speter * fmtstart = 0 for leading blank; = 1 for no blank 239766Speter */ 240766Speter fmtspec = NIL; 241766Speter stkcnt = 0; 242766Speter fmt = 'D'; 243766Speter fmtstart = 1; 244766Speter al = argv[1]; 245766Speter if (al == NIL) 246766Speter continue; 247766Speter if (al[0] == T_WEXP) 248766Speter alv = al[1]; 249766Speter else 250766Speter alv = al; 251766Speter if (alv == NIL) 252766Speter continue; 253766Speter codeoff(); 254766Speter ap = stkrval(alv, NIL , RREQ ); 255766Speter codeon(); 256766Speter if (ap == NIL) 257766Speter continue; 258766Speter typ = classify(ap); 259766Speter if (al[0] == T_WEXP) { 260766Speter /* 261766Speter * Handle width expressions. 262766Speter * The basic game here is that width 263766Speter * expressions get evaluated. If they 264766Speter * are constant, the value is placed 265766Speter * directly in the format string. 266766Speter * Otherwise the value is pushed onto 267766Speter * the stack and an indirection is 268766Speter * put into the format string. 269766Speter */ 270766Speter if (al[3] == OCT) 271766Speter fmt = 'O'; 272766Speter else if (al[3] == HEX) 273766Speter fmt = 'X'; 274766Speter else if (al[3] != NIL) { 275766Speter /* 276766Speter * Evaluate second format spec 277766Speter */ 278766Speter if ( constval(al[3]) 279766Speter && isa( con.ctype , "i" ) ) { 280766Speter fmtspec += CONPREC; 281766Speter prec = con.crval; 282766Speter } else { 283766Speter fmtspec += VARPREC; 284766Speter } 285766Speter fmt = 'f'; 286766Speter switch ( typ ) { 287766Speter case TINT: 288766Speter if ( opt( 's' ) ) { 289766Speter standard(); 290766Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 291766Speter } 292766Speter /* and fall through */ 293766Speter case TDOUBLE: 294766Speter break; 295766Speter default: 296766Speter error("Cannot write %ss with two write widths", clnames[typ]); 297766Speter continue; 298766Speter } 299766Speter } 300766Speter /* 301766Speter * Evaluate first format spec 302766Speter */ 303766Speter if (al[2] != NIL) { 304766Speter if ( constval(al[2]) 305766Speter && isa( con.ctype , "i" ) ) { 306766Speter fmtspec += CONWIDTH; 307766Speter field = con.crval; 308766Speter } else { 309766Speter fmtspec += VARWIDTH; 310766Speter } 311766Speter } 312766Speter if ((fmtspec & CONPREC) && prec < 0 || 313766Speter (fmtspec & CONWIDTH) && field < 0) { 314766Speter error("Negative widths are not allowed"); 315766Speter continue; 316766Speter } 3173180Smckusic if ( opt('s') && 3183180Smckusic ((fmtspec & CONPREC) && prec == 0 || 3193180Smckusic (fmtspec & CONWIDTH) && field == 0)) { 3203180Smckusic standard(); 3213180Smckusic error("Zero widths are non-standard"); 3223180Smckusic } 323766Speter } 324766Speter if (filetype != nl+T1CHAR) { 325766Speter if (fmt == 'O' || fmt == 'X') { 326766Speter error("Oct/hex allowed only on text files"); 327766Speter continue; 328766Speter } 329766Speter if (fmtspec) { 330766Speter error("Write widths allowed only on text files"); 331766Speter continue; 332766Speter } 333766Speter /* 334766Speter * Generalized write, i.e. 335766Speter * to a non-textfile. 336766Speter */ 337766Speter putleaf( P2ICON , 0 , 0 338766Speter , ADDTYPE( 339766Speter ADDTYPE( 340766Speter ADDTYPE( p2type( filetype ) 341766Speter , P2PTR ) 342766Speter , P2FTN ) 343766Speter , P2PTR ) 344766Speter , "_FNIL" ); 345766Speter stklval(file, NOFLAGS); 346766Speter putop( P2CALL 347766Speter , ADDTYPE( p2type( filetype ) , P2PTR ) ); 348766Speter putop( P2UNARY P2MUL , p2type( filetype ) ); 349766Speter /* 350766Speter * file^ := ... 351766Speter */ 352766Speter switch ( classify( filetype ) ) { 353766Speter case TBOOL: 354766Speter case TCHAR: 355766Speter case TINT: 356766Speter case TSCAL: 3574589Speter precheck( filetype , "_RANG4" , "_RSNG4" ); 358766Speter /* and fall through */ 359766Speter case TDOUBLE: 360766Speter case TPTR: 361766Speter ap = rvalue( argv[1] , filetype , RREQ ); 362766Speter break; 363766Speter default: 364766Speter ap = rvalue( argv[1] , filetype , LREQ ); 365766Speter break; 366766Speter } 367766Speter if (ap == NIL) 368766Speter continue; 369766Speter if (incompat(ap, filetype, argv[1])) { 370766Speter cerror("Type mismatch in write to non-text file"); 371766Speter continue; 372766Speter } 373766Speter switch ( classify( filetype ) ) { 374766Speter case TBOOL: 375766Speter case TCHAR: 376766Speter case TINT: 377766Speter case TSCAL: 378766Speter postcheck( filetype ); 379766Speter /* and fall through */ 380766Speter case TDOUBLE: 381766Speter case TPTR: 382766Speter putop( P2ASSIGN , p2type( filetype ) ); 383766Speter putdot( filename , line ); 384766Speter break; 385766Speter default: 386766Speter putstrop( P2STASG 387766Speter , p2type( filetype ) 388766Speter , lwidth( filetype ) 389766Speter , align( filetype ) ); 390766Speter putdot( filename , line ); 391766Speter break; 392766Speter } 393766Speter /* 394766Speter * put(file) 395766Speter */ 396766Speter putleaf( P2ICON , 0 , 0 397766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 398766Speter , "_PUT" ); 3993833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 4003833Speter P2PTR|P2STRTY ); 401766Speter putop( P2CALL , P2INT ); 402766Speter putdot( filename , line ); 403766Speter continue; 404766Speter } 405766Speter /* 406766Speter * Write to a textfile 407766Speter * 408766Speter * Evaluate the expression 409766Speter * to be written. 410766Speter */ 411766Speter if (fmt == 'O' || fmt == 'X') { 412766Speter if (opt('s')) { 413766Speter standard(); 414766Speter error("Oct and hex are non-standard"); 415766Speter } 416766Speter if (typ == TSTR || typ == TDOUBLE) { 417766Speter error("Can't write %ss with oct/hex", clnames[typ]); 418766Speter continue; 419766Speter } 420766Speter if (typ == TCHAR || typ == TBOOL) 421766Speter typ = TINT; 422766Speter } 423766Speter /* 424766Speter * If there is no format specified by the programmer, 425766Speter * implement the default. 426766Speter */ 427766Speter switch (typ) { 4286540Smckusick case TPTR: 4296540Smckusick warning(); 4306540Smckusick if (opt('s')) { 4316540Smckusick standard(); 4326540Smckusick } 4336540Smckusick error("Writing %ss to text files is non-standard", 4346540Smckusick clnames[typ]); 4356540Smckusick /* and fall through */ 436766Speter case TINT: 437766Speter if (fmt == 'f') { 438766Speter typ = TDOUBLE; 439766Speter goto tdouble; 440766Speter } 441766Speter if (fmtspec == NIL) { 442766Speter if (fmt == 'D') 443766Speter field = 10; 444766Speter else if (fmt == 'X') 445766Speter field = 8; 446766Speter else if (fmt == 'O') 447766Speter field = 11; 448766Speter else 449766Speter panic("fmt1"); 450766Speter fmtspec = CONWIDTH; 451766Speter } 452766Speter break; 453766Speter case TCHAR: 454766Speter tchar: 455766Speter fmt = 'c'; 456766Speter break; 457766Speter case TSCAL: 4581629Speter warning(); 459766Speter if (opt('s')) { 460766Speter standard(); 461766Speter } 4626540Smckusick error("Writing %ss to text files is non-standard", 4636540Smckusick clnames[typ]); 464766Speter case TBOOL: 465766Speter fmt = 's'; 466766Speter break; 467766Speter case TDOUBLE: 468766Speter tdouble: 469766Speter switch (fmtspec) { 470766Speter case NIL: 471766Speter field = 21; 472766Speter prec = 14; 4733225Smckusic fmt = 'e'; 474766Speter fmtspec = CONWIDTH + CONPREC; 475766Speter break; 476766Speter case CONWIDTH: 477766Speter if (--field < 1) 478766Speter field = 1; 479766Speter prec = field - 7; 480766Speter if (prec < 1) 481766Speter prec = 1; 482766Speter fmtspec += CONPREC; 4833225Smckusic fmt = 'e'; 484766Speter break; 485766Speter case VARWIDTH: 486766Speter fmtspec += VARPREC; 4873225Smckusic fmt = 'e'; 488766Speter break; 489766Speter case CONWIDTH + CONPREC: 490766Speter case CONWIDTH + VARPREC: 491766Speter if (--field < 1) 492766Speter field = 1; 493766Speter } 494766Speter format[0] = ' '; 4958025Smckusick fmtstart = 1; 496766Speter break; 497766Speter case TSTR: 498766Speter constval( alv ); 499766Speter switch ( classify( con.ctype ) ) { 500766Speter case TCHAR: 501766Speter typ = TCHAR; 502766Speter goto tchar; 503766Speter case TSTR: 504766Speter strptr = con.cpval; 505766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 506766Speter strptr = con.cpval; 507766Speter break; 508766Speter default: 509766Speter strnglen = width(ap); 510766Speter break; 511766Speter } 512766Speter fmt = 's'; 513766Speter strfmt = fmtspec; 514766Speter if (fmtspec == NIL) { 515766Speter fmtspec = SKIP; 516766Speter break; 517766Speter } 518766Speter if (fmtspec & CONWIDTH) { 519766Speter if (field <= strnglen) 520766Speter fmtspec = SKIP; 521766Speter else 522766Speter field -= strnglen; 523766Speter } 524766Speter break; 525766Speter default: 526766Speter error("Can't write %ss to a text file", clnames[typ]); 527766Speter continue; 528766Speter } 529766Speter /* 530766Speter * Generate the format string 531766Speter */ 532766Speter switch (fmtspec) { 533766Speter default: 534766Speter panic("fmt2"); 535766Speter case NIL: 536766Speter if (fmt == 'c') { 537766Speter if ( opt( 't' ) ) { 538766Speter putleaf( P2ICON , 0 , 0 539766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 540766Speter , "_WRITEC" ); 5413833Speter putRV( 0 , cbn , CURFILEOFFSET , 5423833Speter NLOCAL , P2PTR|P2STRTY ); 543766Speter stkrval( alv , NIL , RREQ ); 544766Speter putop( P2LISTOP , P2INT ); 545766Speter } else { 546766Speter putleaf( P2ICON , 0 , 0 547766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 548766Speter , "_fputc" ); 549766Speter stkrval( alv , NIL , RREQ ); 550766Speter } 551766Speter putleaf( P2ICON , 0 , 0 552766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 553766Speter , "_ACTFILE" ); 5543833Speter putRV( 0, cbn , CURFILEOFFSET , 5553833Speter NLOCAL , P2PTR|P2STRTY ); 556766Speter putop( P2CALL , P2INT ); 557766Speter putop( P2LISTOP , P2INT ); 558766Speter putop( P2CALL , P2INT ); 559766Speter putdot( filename , line ); 560766Speter } else { 561766Speter sprintf(&format[1], "%%%c", fmt); 562766Speter goto fmtgen; 563766Speter } 564766Speter case SKIP: 565766Speter break; 566766Speter case CONWIDTH: 567766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 568766Speter goto fmtgen; 569766Speter case VARWIDTH: 570766Speter sprintf(&format[1], "%%*%c", fmt); 571766Speter goto fmtgen; 572766Speter case CONWIDTH + CONPREC: 573766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 574766Speter goto fmtgen; 575766Speter case CONWIDTH + VARPREC: 576766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 577766Speter goto fmtgen; 578766Speter case VARWIDTH + CONPREC: 579766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 580766Speter goto fmtgen; 581766Speter case VARWIDTH + VARPREC: 582766Speter sprintf(&format[1], "%%*.*%c", fmt); 583766Speter fmtgen: 584766Speter if ( opt( 't' ) ) { 585766Speter putleaf( P2ICON , 0 , 0 586766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 587766Speter , "_WRITEF" ); 5883833Speter putRV( 0 , cbn , CURFILEOFFSET , 5893833Speter NLOCAL , P2PTR|P2STRTY ); 590766Speter putleaf( P2ICON , 0 , 0 591766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 592766Speter , "_ACTFILE" ); 5933833Speter putRV( 0 , cbn , CURFILEOFFSET , 5943833Speter NLOCAL , P2PTR|P2STRTY ); 595766Speter putop( P2CALL , P2INT ); 596766Speter putop( P2LISTOP , P2INT ); 597766Speter } else { 598766Speter putleaf( P2ICON , 0 , 0 599766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 600766Speter , "_fprintf" ); 601766Speter putleaf( P2ICON , 0 , 0 602766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 603766Speter , "_ACTFILE" ); 6043833Speter putRV( 0 , cbn , CURFILEOFFSET , 6053833Speter NLOCAL , P2PTR|P2STRTY ); 606766Speter putop( P2CALL , P2INT ); 607766Speter } 608766Speter putCONG( &format[ fmtstart ] 609766Speter , strlen( &format[ fmtstart ] ) 610766Speter , LREQ ); 611766Speter putop( P2LISTOP , P2INT ); 612766Speter if ( fmtspec & VARWIDTH ) { 613766Speter /* 614766Speter * either 615766Speter * ,(temp=width,MAX(temp,...)), 616766Speter * or 617766Speter * , MAX( width , ... ) , 618766Speter */ 619766Speter if ( ( typ == TDOUBLE && al[3] == NIL ) 620766Speter || typ == TSTR ) { 6213225Smckusic soffset = sizes[cbn].curtmps; 6223833Speter tempnlp = tmpalloc(sizeof(long), 6233225Smckusic nl+T4INT, REGOK); 6243833Speter putRV( 0 , cbn , 6253833Speter tempnlp -> value[ NL_OFFS ] , 6263833Speter tempnlp -> extra_flags , P2INT ); 627766Speter ap = stkrval( al[2] , NIL , RREQ ); 628766Speter putop( P2ASSIGN , P2INT ); 629766Speter putleaf( P2ICON , 0 , 0 630766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 631766Speter , "_MAX" ); 6323833Speter putRV( 0 , cbn , 6333833Speter tempnlp -> value[ NL_OFFS ] , 6343833Speter tempnlp -> extra_flags , P2INT ); 635766Speter } else { 636766Speter if (opt('t') 637766Speter || typ == TSTR || typ == TDOUBLE) { 638766Speter putleaf( P2ICON , 0 , 0 639766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 640766Speter ,"_MAX" ); 641766Speter } 642766Speter ap = stkrval( al[2] , NIL , RREQ ); 643766Speter } 644766Speter if (ap == NIL) 645766Speter continue; 646766Speter if (isnta(ap,"i")) { 647766Speter error("First write width must be integer, not %s", nameof(ap)); 648766Speter continue; 649766Speter } 650766Speter switch ( typ ) { 651766Speter case TDOUBLE: 652766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 653766Speter putop( P2LISTOP , P2INT ); 654766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 655766Speter putop( P2LISTOP , P2INT ); 656766Speter putop( P2CALL , P2INT ); 657766Speter if ( al[3] == NIL ) { 658766Speter /* 659766Speter * finish up the comma op 660766Speter */ 661766Speter putop( P2COMOP , P2INT ); 662766Speter fmtspec &= ~VARPREC; 663766Speter putop( P2LISTOP , P2INT ); 664766Speter putleaf( P2ICON , 0 , 0 665766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 666766Speter , "_MAX" ); 6673833Speter putRV( 0 , cbn , 6683833Speter tempnlp -> value[ NL_OFFS ] , 6693833Speter tempnlp -> extra_flags , 6703833Speter P2INT ); 6713225Smckusic tmpfree(&soffset); 672766Speter putleaf( P2ICON , 8 , 0 , P2INT , 0 ); 673766Speter putop( P2LISTOP , P2INT ); 674766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 675766Speter putop( P2LISTOP , P2INT ); 676766Speter putop( P2CALL , P2INT ); 677766Speter } 678766Speter putop( P2LISTOP , P2INT ); 679766Speter break; 680766Speter case TSTR: 681766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 682766Speter putop( P2LISTOP , P2INT ); 683766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 684766Speter putop( P2LISTOP , P2INT ); 685766Speter putop( P2CALL , P2INT ); 686766Speter putop( P2COMOP , P2INT ); 687766Speter putop( P2LISTOP , P2INT ); 688766Speter break; 689766Speter default: 690766Speter if (opt('t')) { 691766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 692766Speter putop( P2LISTOP , P2INT ); 693766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 694766Speter putop( P2LISTOP , P2INT ); 695766Speter putop( P2CALL , P2INT ); 696766Speter } 697766Speter putop( P2LISTOP , P2INT ); 698766Speter break; 699766Speter } 700766Speter } 701766Speter /* 702766Speter * If there is a variable precision, 703766Speter * evaluate it 704766Speter */ 705766Speter if (fmtspec & VARPREC) { 706766Speter if (opt('t')) { 707766Speter putleaf( P2ICON , 0 , 0 708766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 709766Speter , "_MAX" ); 710766Speter } 711766Speter ap = stkrval( al[3] , NIL , RREQ ); 712766Speter if (ap == NIL) 713766Speter continue; 714766Speter if (isnta(ap,"i")) { 715766Speter error("Second write width must be integer, not %s", nameof(ap)); 716766Speter continue; 717766Speter } 718766Speter if (opt('t')) { 719766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 720766Speter putop( P2LISTOP , P2INT ); 721766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 722766Speter putop( P2LISTOP , P2INT ); 723766Speter putop( P2CALL , P2INT ); 724766Speter } 725766Speter putop( P2LISTOP , P2INT ); 726766Speter } 727766Speter /* 728766Speter * evaluate the thing we want printed. 729766Speter */ 730766Speter switch ( typ ) { 7316540Smckusick case TPTR: 732766Speter case TCHAR: 733766Speter case TINT: 734766Speter stkrval( alv , NIL , RREQ ); 735766Speter putop( P2LISTOP , P2INT ); 736766Speter break; 737766Speter case TDOUBLE: 738766Speter ap = stkrval( alv , NIL , RREQ ); 739766Speter if ( isnta( ap , "d" ) ) { 740766Speter putop( P2SCONV , P2DOUBLE ); 741766Speter } 742766Speter putop( P2LISTOP , P2INT ); 743766Speter break; 744766Speter case TSCAL: 745766Speter case TBOOL: 746766Speter putleaf( P2ICON , 0 , 0 747766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 748766Speter , "_NAM" ); 749766Speter ap = stkrval( alv , NIL , RREQ ); 750766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 751766Speter , listnames( ap ) ); 752766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 753766Speter , format ); 754766Speter putop( P2LISTOP , P2INT ); 755766Speter putop( P2CALL , P2INT ); 756766Speter putop( P2LISTOP , P2INT ); 757766Speter break; 758766Speter case TSTR: 759766Speter putCONG( "" , 0 , LREQ ); 760766Speter putop( P2LISTOP , P2INT ); 761766Speter break; 7626540Smckusick default: 7636540Smckusick panic("fmt3"); 7646540Smckusick break; 765766Speter } 766766Speter putop( P2CALL , P2INT ); 767766Speter putdot( filename , line ); 768766Speter } 769766Speter /* 770766Speter * Write the string after its blank padding 771766Speter */ 772766Speter if (typ == TSTR ) { 773766Speter if ( opt( 't' ) ) { 774766Speter putleaf( P2ICON , 0 , 0 775766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 776766Speter , "_WRITES" ); 7773833Speter putRV( 0 , cbn , CURFILEOFFSET , 7783833Speter NLOCAL , P2PTR|P2STRTY ); 779766Speter ap = stkrval(alv, NIL , RREQ ); 780766Speter putop( P2LISTOP , P2INT ); 781766Speter } else { 782766Speter putleaf( P2ICON , 0 , 0 783766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 784766Speter , "_fwrite" ); 785766Speter ap = stkrval(alv, NIL , RREQ ); 786766Speter } 787766Speter if (strfmt & VARWIDTH) { 788766Speter /* 789766Speter * min, inline expanded as 790766Speter * temp < len ? temp : len 791766Speter */ 7923833Speter putRV( 0 , cbn , 7933833Speter tempnlp -> value[ NL_OFFS ] , 7943833Speter tempnlp -> extra_flags , P2INT ); 795766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 796766Speter putop( P2LT , P2INT ); 7973833Speter putRV( 0 , cbn , 7983833Speter tempnlp -> value[ NL_OFFS ] , 7993833Speter tempnlp -> extra_flags , P2INT ); 800766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 801766Speter putop( P2COLON , P2INT ); 802766Speter putop( P2QUEST , P2INT ); 8033225Smckusic tmpfree(&soffset); 804766Speter } else { 805766Speter if ( ( fmtspec & SKIP ) 806766Speter && ( strfmt & CONWIDTH ) ) { 807766Speter strnglen = field; 808766Speter } 809766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 810766Speter } 811766Speter putop( P2LISTOP , P2INT ); 812766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 813766Speter putop( P2LISTOP , P2INT ); 814766Speter putleaf( P2ICON , 0 , 0 815766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 816766Speter , "_ACTFILE" ); 8173833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 8183833Speter P2PTR|P2STRTY ); 819766Speter putop( P2CALL , P2INT ); 820766Speter putop( P2LISTOP , P2INT ); 821766Speter putop( P2CALL , P2INT ); 822766Speter putdot( filename , line ); 823766Speter } 824766Speter } 825766Speter /* 826766Speter * Done with arguments. 827766Speter * Handle writeln and 828766Speter * insufficent number of args. 829766Speter */ 830766Speter switch (p->value[0] &~ NSTAND) { 831766Speter case O_WRITEF: 832766Speter if (argc == 0) 833766Speter error("Write requires an argument"); 834766Speter break; 835766Speter case O_MESSAGE: 836766Speter if (argc == 0) 837766Speter error("Message requires an argument"); 838766Speter case O_WRITLN: 839766Speter if (filetype != nl+T1CHAR) 840766Speter error("Can't 'writeln' a non text file"); 841766Speter if ( opt( 't' ) ) { 842766Speter putleaf( P2ICON , 0 , 0 843766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 844766Speter , "_WRITLN" ); 8453833Speter putRV( 0 , cbn , CURFILEOFFSET , 8463833Speter NLOCAL , P2PTR|P2STRTY ); 847766Speter } else { 848766Speter putleaf( P2ICON , 0 , 0 849766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 850766Speter , "_fputc" ); 851766Speter putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 ); 852766Speter putleaf( P2ICON , 0 , 0 853766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 854766Speter , "_ACTFILE" ); 8553833Speter putRV( 0 , cbn , CURFILEOFFSET , 8563833Speter NLOCAL , P2PTR|P2STRTY ); 857766Speter putop( P2CALL , P2INT ); 858766Speter putop( P2LISTOP , P2INT ); 859766Speter } 860766Speter putop( P2CALL , P2INT ); 861766Speter putdot( filename , line ); 862766Speter break; 863766Speter } 864766Speter return; 865766Speter 866766Speter case O_READ4: 867766Speter case O_READLN: 868766Speter /* 869766Speter * Set up default 870766Speter * file "input". 871766Speter */ 872766Speter file = NIL; 873766Speter filetype = nl+T1CHAR; 874766Speter /* 875766Speter * Determine the file implied 876766Speter * for the read and generate 877766Speter * code to make it the active file. 878766Speter */ 879766Speter if (argv != NIL) { 880766Speter codeoff(); 881766Speter ap = stkrval(argv[1], NIL , RREQ ); 882766Speter codeon(); 883766Speter if (ap == NIL) 884766Speter argv = argv[2]; 885766Speter if (ap != NIL && ap->class == FILET) { 886766Speter /* 887766Speter * Got "read(f, ...", make 888766Speter * f the active file, and save 889766Speter * it and its type for use in 890766Speter * processing the rest of the 891766Speter * arguments to read. 892766Speter */ 893766Speter file = argv[1]; 894766Speter filetype = ap->type; 8953833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 8963833Speter P2PTR|P2STRTY ); 897766Speter putleaf( P2ICON , 0 , 0 898766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 899766Speter , "_UNIT" ); 900766Speter stklval(argv[1], NOFLAGS); 901766Speter putop( P2CALL , P2INT ); 902766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 903766Speter putdot( filename , line ); 904766Speter argv = argv[2]; 905766Speter argc--; 906766Speter } else { 907766Speter /* 908766Speter * Default is read from 909766Speter * standard input. 910766Speter */ 9113833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9123833Speter P2PTR|P2STRTY ); 9133833Speter putLV( "_input" , 0 , 0 , NGLOBAL , 9143833Speter P2PTR|P2STRTY ); 915766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 916766Speter putdot( filename , line ); 917766Speter input->nl_flags |= NUSED; 918766Speter } 919766Speter } else { 9203833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9213833Speter P2PTR|P2STRTY ); 9223833Speter putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 923766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 924766Speter putdot( filename , line ); 925766Speter input->nl_flags |= NUSED; 926766Speter } 927766Speter /* 928766Speter * Loop and process each 929766Speter * of the arguments. 930766Speter */ 931766Speter for (; argv != NIL; argv = argv[2]) { 932766Speter /* 933766Speter * Get the address of the target 934766Speter * on the stack. 935766Speter */ 936766Speter al = argv[1]; 937766Speter if (al == NIL) 938766Speter continue; 939766Speter if (al[0] != T_VAR) { 940766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 941766Speter continue; 942766Speter } 943766Speter codeoff(); 944766Speter ap = stklval(al, MOD|ASGN|NOUSE); 945766Speter codeon(); 946766Speter if (ap == NIL) 947766Speter continue; 948766Speter if (filetype != nl+T1CHAR) { 949766Speter /* 950766Speter * Generalized read, i.e. 951766Speter * from a non-textfile. 952766Speter */ 953766Speter if (incompat(filetype, ap, argv[1] )) { 954766Speter error("Type mismatch in read from non-text file"); 955766Speter continue; 956766Speter } 957766Speter /* 958766Speter * var := file ^; 959766Speter */ 960766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 961766Speter if ( isa( ap , "bsci" ) ) { 962766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 963766Speter } 964766Speter putleaf( P2ICON , 0 , 0 965766Speter , ADDTYPE( 966766Speter ADDTYPE( 967766Speter ADDTYPE( 968766Speter p2type( filetype ) , P2PTR ) 969766Speter , P2FTN ) 970766Speter , P2PTR ) 971766Speter , "_FNIL" ); 972766Speter if (file != NIL) 973766Speter stklval(file, NOFLAGS); 974766Speter else /* Magic */ 9753833Speter putRV( "_input" , 0 , 0 , NGLOBAL , 9763833Speter P2PTR | P2STRTY ); 977766Speter putop( P2CALL , P2INT ); 978766Speter switch ( classify( filetype ) ) { 979766Speter case TBOOL: 980766Speter case TCHAR: 981766Speter case TINT: 982766Speter case TSCAL: 983766Speter case TDOUBLE: 984766Speter case TPTR: 985766Speter putop( P2UNARY P2MUL 986766Speter , p2type( filetype ) ); 987766Speter } 988766Speter switch ( classify( filetype ) ) { 989766Speter case TBOOL: 990766Speter case TCHAR: 991766Speter case TINT: 992766Speter case TSCAL: 993766Speter postcheck( ap ); 994766Speter /* and fall through */ 995766Speter case TDOUBLE: 996766Speter case TPTR: 997766Speter putop( P2ASSIGN , p2type( ap ) ); 998766Speter putdot( filename , line ); 999766Speter break; 1000766Speter default: 1001766Speter putstrop( P2STASG 1002766Speter , p2type( ap ) 1003766Speter , lwidth( ap ) 1004766Speter , align( ap ) ); 1005766Speter putdot( filename , line ); 1006766Speter break; 1007766Speter } 1008766Speter /* 1009766Speter * get(file); 1010766Speter */ 1011766Speter putleaf( P2ICON , 0 , 0 1012766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1013766Speter , "_GET" ); 10143833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10153833Speter P2PTR|P2STRTY ); 1016766Speter putop( P2CALL , P2INT ); 1017766Speter putdot( filename , line ); 1018766Speter continue; 1019766Speter } 1020766Speter /* 1021766Speter * if you get to here, you are reading from 1022766Speter * a text file. only possiblities are: 1023766Speter * character, integer, real, or scalar. 1024766Speter * read( f , foo , ... ) is done as 1025766Speter * foo := read( f ) with rangechecking 1026766Speter * if appropriate. 1027766Speter */ 1028766Speter typ = classify(ap); 1029766Speter op = rdops(typ); 1030766Speter if (op == NIL) { 1031766Speter error("Can't read %ss from a text file", clnames[typ]); 1032766Speter continue; 1033766Speter } 1034766Speter /* 1035766Speter * left hand side of foo := read( f ) 1036766Speter */ 1037766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 1038766Speter if ( isa( ap , "bsci" ) ) { 1039766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1040766Speter } 1041766Speter switch ( op ) { 1042766Speter case O_READC: 1043766Speter readname = "_READC"; 1044766Speter readtype = P2INT; 1045766Speter break; 1046766Speter case O_READ4: 1047766Speter readname = "_READ4"; 1048766Speter readtype = P2INT; 1049766Speter break; 1050766Speter case O_READ8: 1051766Speter readname = "_READ8"; 1052766Speter readtype = P2DOUBLE; 1053766Speter break; 1054766Speter case O_READE: 1055766Speter readname = "_READE"; 1056766Speter readtype = P2INT; 1057766Speter break; 1058766Speter } 1059766Speter putleaf( P2ICON , 0 , 0 1060766Speter , ADDTYPE( P2FTN | readtype , P2PTR ) 1061766Speter , readname ); 10623833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10633833Speter P2PTR|P2STRTY ); 1064766Speter if ( op == O_READE ) { 1065766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1066766Speter , listnames( ap ) ); 1067766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 1068766Speter , format ); 1069766Speter putop( P2LISTOP , P2INT ); 10701629Speter warning(); 1071766Speter if (opt('s')) { 1072766Speter standard(); 1073766Speter } 10741629Speter error("Reading scalars from text files is non-standard"); 1075766Speter } 1076766Speter putop( P2CALL , readtype ); 1077766Speter if ( isa( ap , "bcsi" ) ) { 1078766Speter postcheck( ap ); 1079766Speter } 1080766Speter putop( P2ASSIGN , p2type( ap ) ); 1081766Speter putdot( filename , line ); 1082766Speter } 1083766Speter /* 1084766Speter * Done with arguments. 1085766Speter * Handle readln and 1086766Speter * insufficient number of args. 1087766Speter */ 1088766Speter if (p->value[0] == O_READLN) { 1089766Speter if (filetype != nl+T1CHAR) 1090766Speter error("Can't 'readln' a non text file"); 1091766Speter putleaf( P2ICON , 0 , 0 1092766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1093766Speter , "_READLN" ); 10943833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10953833Speter P2PTR|P2STRTY ); 1096766Speter putop( P2CALL , P2INT ); 1097766Speter putdot( filename , line ); 1098766Speter } else if (argc == 0) 1099766Speter error("read requires an argument"); 1100766Speter return; 1101766Speter 1102766Speter case O_GET: 1103766Speter case O_PUT: 1104766Speter if (argc != 1) { 1105766Speter error("%s expects one argument", p->symbol); 1106766Speter return; 1107766Speter } 11083833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1109766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1110766Speter , "_UNIT" ); 1111766Speter ap = stklval(argv[1], NOFLAGS); 1112766Speter if (ap == NIL) 1113766Speter return; 1114766Speter if (ap->class != FILET) { 1115766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1116766Speter return; 1117766Speter } 1118766Speter putop( P2CALL , P2INT ); 1119766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1120766Speter putdot( filename , line ); 1121766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1122766Speter , op == O_GET ? "_GET" : "_PUT" ); 11233833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1124766Speter putop( P2CALL , P2INT ); 1125766Speter putdot( filename , line ); 1126766Speter return; 1127766Speter 1128766Speter case O_RESET: 1129766Speter case O_REWRITE: 1130766Speter if (argc == 0 || argc > 2) { 1131766Speter error("%s expects one or two arguments", p->symbol); 1132766Speter return; 1133766Speter } 1134766Speter if (opt('s') && argc == 2) { 1135766Speter standard(); 1136766Speter error("Two argument forms of reset and rewrite are non-standard"); 1137766Speter } 1138766Speter putleaf( P2ICON , 0 , 0 , P2INT 1139766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 1140766Speter ap = stklval(argv[1], MOD|NOUSE); 1141766Speter if (ap == NIL) 1142766Speter return; 1143766Speter if (ap->class != FILET) { 1144766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1145766Speter return; 1146766Speter } 1147766Speter if (argc == 2) { 1148766Speter /* 1149766Speter * Optional second argument 1150766Speter * is a string name of a 1151766Speter * UNIX (R) file to be associated. 1152766Speter */ 1153766Speter al = argv[2]; 1154766Speter al = stkrval(al[1], NOFLAGS , RREQ ); 1155766Speter if (al == NIL) 1156766Speter return; 1157766Speter if (classify(al) != TSTR) { 1158766Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 1159766Speter return; 1160766Speter } 1161766Speter strnglen = width(al); 1162766Speter } else { 1163766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 1164766Speter strnglen = 0; 1165766Speter } 1166766Speter putop( P2LISTOP , P2INT ); 1167766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 1168766Speter putop( P2LISTOP , P2INT ); 1169766Speter putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 ); 1170766Speter putop( P2LISTOP , P2INT ); 1171766Speter putop( P2CALL , P2INT ); 1172766Speter putdot( filename , line ); 1173766Speter return; 1174766Speter 1175766Speter case O_NEW: 1176766Speter case O_DISPOSE: 1177766Speter if (argc == 0) { 1178766Speter error("%s expects at least one argument", p->symbol); 1179766Speter return; 1180766Speter } 1181*9139Smckusick alv = argv[1]; 11827967Smckusick codeoff(); 1183*9139Smckusick ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 11847967Smckusick codeon(); 1185766Speter if (ap == NIL) 1186766Speter return; 1187766Speter if (ap->class != PTR) { 1188766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1189766Speter return; 1190766Speter } 1191766Speter ap = ap->type; 1192766Speter if (ap == NIL) 1193766Speter return; 1194*9139Smckusick if (op == O_NEW) 1195*9139Smckusick cmd = "_NEW"; 1196*9139Smckusick else /* op == O_DISPOSE */ 11977967Smckusick if ((ap->nl_flags & NFILES) != 0) 11987967Smckusick cmd = "_DFDISPOSE"; 11997967Smckusick else 12007967Smckusick cmd = "_DISPOSE"; 12017967Smckusick putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd); 1202*9139Smckusick stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1203766Speter argv = argv[2]; 1204766Speter if (argv != NIL) { 1205766Speter if (ap->class != RECORD) { 1206766Speter error("Record required when specifying variant tags"); 1207766Speter return; 1208766Speter } 1209766Speter for (; argv != NIL; argv = argv[2]) { 1210766Speter if (ap->ptr[NL_VARNT] == NIL) { 1211766Speter error("Too many tag fields"); 1212766Speter return; 1213766Speter } 1214766Speter if (!isconst(argv[1])) { 1215766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1216766Speter return; 1217766Speter } 1218766Speter gconst(argv[1]); 1219766Speter if (con.ctype == NIL) 1220766Speter return; 1221766Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 1222766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1223766Speter return; 1224766Speter } 1225766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1226766Speter if (ap->range[0] == con.crval) 1227766Speter break; 1228766Speter if (ap == NIL) { 1229766Speter error("No variant case label value equals specified constant value"); 1230766Speter return; 1231766Speter } 1232766Speter ap = ap->ptr[NL_VTOREC]; 1233766Speter } 1234766Speter } 1235766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1236766Speter putop( P2LISTOP , P2INT ); 1237766Speter putop( P2CALL , P2INT ); 1238766Speter putdot( filename , line ); 1239*9139Smckusick if (opt('t') && op == O_NEW) { 1240*9139Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1241*9139Smckusick , "_blkclr" ); 1242*9139Smckusick stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1243*9139Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1244*9139Smckusick putop( P2LISTOP , P2INT ); 1245*9139Smckusick putop( P2CALL , P2INT ); 1246*9139Smckusick putdot( filename , line ); 1247*9139Smckusick } 1248766Speter return; 1249766Speter 1250766Speter case O_DATE: 1251766Speter case O_TIME: 1252766Speter if (argc != 1) { 1253766Speter error("%s expects one argument", p->symbol); 1254766Speter return; 1255766Speter } 1256766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1257766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 1258766Speter ap = stklval(argv[1], MOD|NOUSE); 1259766Speter if (ap == NIL) 1260766Speter return; 1261766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1262766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1263766Speter return; 1264766Speter } 1265766Speter putop( P2CALL , P2INT ); 1266766Speter putdot( filename , line ); 1267766Speter return; 1268766Speter 1269766Speter case O_HALT: 1270766Speter if (argc != 0) { 1271766Speter error("halt takes no arguments"); 1272766Speter return; 1273766Speter } 1274766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1275766Speter , "_HALT" ); 1276766Speter 1277766Speter putop( P2UNARY P2CALL , P2INT ); 1278766Speter putdot( filename , line ); 1279766Speter noreach = 1; 1280766Speter return; 1281766Speter 1282766Speter case O_ARGV: 1283766Speter if (argc != 2) { 1284766Speter error("argv takes two arguments"); 1285766Speter return; 1286766Speter } 1287766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1288766Speter , "_ARGV" ); 1289766Speter ap = stkrval(argv[1], NIL , RREQ ); 1290766Speter if (ap == NIL) 1291766Speter return; 1292766Speter if (isnta(ap, "i")) { 1293766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1294766Speter return; 1295766Speter } 1296766Speter al = argv[2]; 1297766Speter ap = stklval(al[1], MOD|NOUSE); 1298766Speter if (ap == NIL) 1299766Speter return; 1300766Speter if (classify(ap) != TSTR) { 1301766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1302766Speter return; 1303766Speter } 1304766Speter putop( P2LISTOP , P2INT ); 1305766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1306766Speter putop( P2LISTOP , P2INT ); 1307766Speter putop( P2CALL , P2INT ); 1308766Speter putdot( filename , line ); 1309766Speter return; 1310766Speter 1311766Speter case O_STLIM: 1312766Speter if (argc != 1) { 1313766Speter error("stlimit requires one argument"); 1314766Speter return; 1315766Speter } 1316766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1317766Speter , "_STLIM" ); 1318766Speter ap = stkrval(argv[1], NIL , RREQ ); 1319766Speter if (ap == NIL) 1320766Speter return; 1321766Speter if (isnta(ap, "i")) { 1322766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1323766Speter return; 1324766Speter } 1325766Speter putop( P2CALL , P2INT ); 1326766Speter putdot( filename , line ); 1327766Speter return; 1328766Speter 1329766Speter case O_REMOVE: 1330766Speter if (argc != 1) { 1331766Speter error("remove expects one argument"); 1332766Speter return; 1333766Speter } 1334766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1335766Speter , "_REMOVE" ); 1336766Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 1337766Speter if (ap == NIL) 1338766Speter return; 1339766Speter if (classify(ap) != TSTR) { 1340766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1341766Speter return; 1342766Speter } 1343766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1344766Speter putop( P2LISTOP , P2INT ); 1345766Speter putop( P2CALL , P2INT ); 1346766Speter putdot( filename , line ); 1347766Speter return; 1348766Speter 1349766Speter case O_LLIMIT: 1350766Speter if (argc != 2) { 1351766Speter error("linelimit expects two arguments"); 1352766Speter return; 1353766Speter } 1354766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1355766Speter , "_LLIMIT" ); 1356766Speter ap = stklval(argv[1], NOFLAGS|NOUSE); 1357766Speter if (ap == NIL) 1358766Speter return; 1359766Speter if (!text(ap)) { 1360766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1361766Speter return; 1362766Speter } 1363766Speter al = argv[2]; 1364766Speter ap = stkrval(al[1], NIL , RREQ ); 1365766Speter if (ap == NIL) 1366766Speter return; 1367766Speter if (isnta(ap, "i")) { 1368766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1369766Speter return; 1370766Speter } 1371766Speter putop( P2LISTOP , P2INT ); 1372766Speter putop( P2CALL , P2INT ); 1373766Speter putdot( filename , line ); 1374766Speter return; 1375766Speter case O_PAGE: 1376766Speter if (argc != 1) { 1377766Speter error("page expects one argument"); 1378766Speter return; 1379766Speter } 13803833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1381766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1382766Speter , "_UNIT" ); 1383766Speter ap = stklval(argv[1], NOFLAGS); 1384766Speter if (ap == NIL) 1385766Speter return; 1386766Speter if (!text(ap)) { 1387766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1388766Speter return; 1389766Speter } 1390766Speter putop( P2CALL , P2INT ); 1391766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1392766Speter putdot( filename , line ); 1393766Speter if ( opt( 't' ) ) { 1394766Speter putleaf( P2ICON , 0 , 0 1395766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1396766Speter , "_PAGE" ); 13973833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1398766Speter } else { 1399766Speter putleaf( P2ICON , 0 , 0 1400766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1401766Speter , "_fputc" ); 1402766Speter putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 ); 1403766Speter putleaf( P2ICON , 0 , 0 1404766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1405766Speter , "_ACTFILE" ); 14063833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1407766Speter putop( P2CALL , P2INT ); 1408766Speter putop( P2LISTOP , P2INT ); 1409766Speter } 1410766Speter putop( P2CALL , P2INT ); 1411766Speter putdot( filename , line ); 1412766Speter return; 1413766Speter 14147928Smckusick case O_ASRT: 14157928Smckusick if (!opt('t')) 14167928Smckusick return; 14177928Smckusick if (argc == 0 || argc > 2) { 14187928Smckusick error("Assert expects one or two arguments"); 14197928Smckusick return; 14207928Smckusick } 1421*9139Smckusick if (argc == 2) 1422*9139Smckusick cmd = "_ASRTS"; 1423*9139Smckusick else 1424*9139Smckusick cmd = "_ASRT"; 14257928Smckusick putleaf( P2ICON , 0 , 0 1426*9139Smckusick , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd ); 14277928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 14287928Smckusick if (ap == NIL) 14297928Smckusick return; 14307928Smckusick if (isnta(ap, "b")) 14317928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 14327928Smckusick if (argc == 2) { 14337928Smckusick /* 14347928Smckusick * Optional second argument is a string specifying 14357928Smckusick * why the assertion failed. 14367928Smckusick */ 14377928Smckusick al = argv[2]; 14387928Smckusick al = stkrval(al[1], NIL , RREQ ); 14397928Smckusick if (al == NIL) 14407928Smckusick return; 14417928Smckusick if (classify(al) != TSTR) { 14427928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 14437928Smckusick return; 14447928Smckusick } 1445*9139Smckusick putop( P2LISTOP , P2INT ); 14467928Smckusick } 14477928Smckusick putop( P2CALL , P2INT ); 14487928Smckusick putdot( filename , line ); 14497928Smckusick return; 14507928Smckusick 1451766Speter case O_PACK: 1452766Speter if (argc != 3) { 1453766Speter error("pack expects three arguments"); 1454766Speter return; 1455766Speter } 1456766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1457766Speter , "_PACK" ); 1458766Speter pu = "pack(a,i,z)"; 1459766Speter pua = (al = argv)[1]; 1460766Speter pui = (al = al[2])[1]; 1461766Speter puz = (al = al[2])[1]; 1462766Speter goto packunp; 1463766Speter case O_UNPACK: 1464766Speter if (argc != 3) { 1465766Speter error("unpack expects three arguments"); 1466766Speter return; 1467766Speter } 1468766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1469766Speter , "_UNPACK" ); 1470766Speter pu = "unpack(z,a,i)"; 1471766Speter puz = (al = argv)[1]; 1472766Speter pua = (al = al[2])[1]; 1473766Speter pui = (al = al[2])[1]; 1474766Speter packunp: 1475766Speter ap = stkrval((int *) pui, NLNIL , RREQ ); 1476766Speter if (ap == NIL) 1477766Speter return; 1478766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1479766Speter if (ap == NIL) 1480766Speter return; 1481766Speter if (ap->class != ARRAY) { 1482766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1483766Speter return; 1484766Speter } 1485766Speter putop( P2LISTOP , P2INT ); 1486766Speter al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1487766Speter if (al->class != ARRAY) { 1488766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1489766Speter return; 1490766Speter } 1491766Speter if (al->type == NIL || ap->type == NIL) 1492766Speter return; 1493766Speter if (al->type != ap->type) { 1494766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1495766Speter return; 1496766Speter } 1497766Speter putop( P2LISTOP , P2INT ); 1498766Speter k = width(al); 1499766Speter itemwidth = width(ap->type); 1500766Speter ap = ap->chain; 1501766Speter al = al->chain; 1502766Speter if (ap->chain != NIL || al->chain != NIL) { 1503766Speter error("%s requires a and z to be single dimension arrays", pu); 1504766Speter return; 1505766Speter } 1506766Speter if (ap == NIL || al == NIL) 1507766Speter return; 1508766Speter /* 1509766Speter * al is the range for z i.e. u..v 1510766Speter * ap is the range for a i.e. m..n 1511766Speter * i will be n-m+1 1512766Speter * j will be v-u+1 1513766Speter */ 1514766Speter i = ap->range[1] - ap->range[0] + 1; 1515766Speter j = al->range[1] - al->range[0] + 1; 1516766Speter if (i < j) { 1517766Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1518766Speter return; 1519766Speter } 1520766Speter /* 1521766Speter * get n-m-(v-u) and m for the interpreter 1522766Speter */ 1523766Speter i -= j; 1524766Speter j = ap->range[0]; 1525766Speter putleaf( P2ICON , itemwidth , 0 , P2INT , 0 ); 1526766Speter putop( P2LISTOP , P2INT ); 1527766Speter putleaf( P2ICON , j , 0 , P2INT , 0 ); 1528766Speter putop( P2LISTOP , P2INT ); 1529766Speter putleaf( P2ICON , i , 0 , P2INT , 0 ); 1530766Speter putop( P2LISTOP , P2INT ); 1531766Speter putleaf( P2ICON , k , 0 , P2INT , 0 ); 1532766Speter putop( P2LISTOP , P2INT ); 1533766Speter putop( P2CALL , P2INT ); 1534766Speter putdot( filename , line ); 1535766Speter return; 1536766Speter case 0: 15377928Smckusick error("%s is an unimplemented extension", p->symbol); 1538766Speter return; 1539766Speter 1540766Speter default: 1541766Speter panic("proc case"); 1542766Speter } 1543766Speter } 1544766Speter #endif PC 1545