1766Speter /* Copyright (c) 1979 Regents of the University of California */ 2766Speter 3*10372Speter static char sccsid[] = "@(#)pcproc.c 1.15.1.3 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" 12*10372Speter #include "objfmt.h" 13766Speter #include "opcode.h" 14*10372Speter #include "pc.h" 15*10372Speter #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: 38910370Speter postcheck( filetype ); 390766Speter /* and fall through */ 391766Speter case TDOUBLE: 392766Speter case TPTR: 393766Speter putop( P2ASSIGN , p2type( filetype ) ); 394766Speter putdot( filename , line ); 395766Speter break; 396766Speter default: 397766Speter putstrop( P2STASG 398766Speter , p2type( filetype ) 399766Speter , lwidth( filetype ) 400766Speter , align( filetype ) ); 401766Speter putdot( filename , line ); 402766Speter break; 403766Speter } 404766Speter /* 405766Speter * put(file) 406766Speter */ 407766Speter putleaf( P2ICON , 0 , 0 408766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 409766Speter , "_PUT" ); 4103833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 4113833Speter P2PTR|P2STRTY ); 412766Speter putop( P2CALL , P2INT ); 413766Speter putdot( filename , line ); 414766Speter continue; 415766Speter } 416766Speter /* 417766Speter * Write to a textfile 418766Speter * 419766Speter * Evaluate the expression 420766Speter * to be written. 421766Speter */ 422766Speter if (fmt == 'O' || fmt == 'X') { 423766Speter if (opt('s')) { 424766Speter standard(); 425766Speter error("Oct and hex are non-standard"); 426766Speter } 427766Speter if (typ == TSTR || typ == TDOUBLE) { 428766Speter error("Can't write %ss with oct/hex", clnames[typ]); 429766Speter continue; 430766Speter } 431766Speter if (typ == TCHAR || typ == TBOOL) 432766Speter typ = TINT; 433766Speter } 434766Speter /* 435766Speter * If there is no format specified by the programmer, 436766Speter * implement the default. 437766Speter */ 438766Speter switch (typ) { 4396540Smckusick case TPTR: 4406540Smckusick warning(); 4416540Smckusick if (opt('s')) { 4426540Smckusick standard(); 4436540Smckusick } 4446540Smckusick error("Writing %ss to text files is non-standard", 4456540Smckusick clnames[typ]); 4466540Smckusick /* and fall through */ 447766Speter case TINT: 448766Speter if (fmt == 'f') { 449766Speter typ = TDOUBLE; 450766Speter goto tdouble; 451766Speter } 452766Speter if (fmtspec == NIL) { 453766Speter if (fmt == 'D') 454766Speter field = 10; 455766Speter else if (fmt == 'X') 456766Speter field = 8; 457766Speter else if (fmt == 'O') 458766Speter field = 11; 459766Speter else 460766Speter panic("fmt1"); 461766Speter fmtspec = CONWIDTH; 462766Speter } 463766Speter break; 464766Speter case TCHAR: 465766Speter tchar: 466766Speter fmt = 'c'; 467766Speter break; 468766Speter case TSCAL: 4691629Speter warning(); 470766Speter if (opt('s')) { 471766Speter standard(); 472766Speter } 4736540Smckusick error("Writing %ss to text files is non-standard", 4746540Smckusick clnames[typ]); 475766Speter case TBOOL: 476766Speter fmt = 's'; 477766Speter break; 478766Speter case TDOUBLE: 479766Speter tdouble: 480766Speter switch (fmtspec) { 481766Speter case NIL: 482766Speter field = 21; 483766Speter prec = 14; 4843225Smckusic fmt = 'e'; 485766Speter fmtspec = CONWIDTH + CONPREC; 486766Speter break; 487766Speter case CONWIDTH: 4889229Smckusick field -= REALSPC; 4899229Smckusick if (field < 1) 490766Speter field = 1; 491766Speter prec = field - 7; 492766Speter if (prec < 1) 493766Speter prec = 1; 494766Speter fmtspec += CONPREC; 4953225Smckusic fmt = 'e'; 496766Speter break; 497766Speter case VARWIDTH: 498766Speter fmtspec += VARPREC; 4993225Smckusic fmt = 'e'; 500766Speter break; 501766Speter case CONWIDTH + CONPREC: 502766Speter case CONWIDTH + VARPREC: 5039229Smckusick field -= REALSPC; 5049229Smckusick if (field < 1) 505766Speter field = 1; 506766Speter } 507766Speter format[0] = ' '; 5089229Smckusick fmtstart = 1 - REALSPC; 509766Speter break; 510766Speter case TSTR: 511766Speter constval( alv ); 512766Speter switch ( classify( con.ctype ) ) { 513766Speter case TCHAR: 514766Speter typ = TCHAR; 515766Speter goto tchar; 516766Speter case TSTR: 517766Speter strptr = con.cpval; 518766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 519766Speter strptr = con.cpval; 520766Speter break; 521766Speter default: 522766Speter strnglen = width(ap); 523766Speter break; 524766Speter } 525766Speter fmt = 's'; 526766Speter strfmt = fmtspec; 527766Speter if (fmtspec == NIL) { 528766Speter fmtspec = SKIP; 529766Speter break; 530766Speter } 531766Speter if (fmtspec & CONWIDTH) { 532766Speter if (field <= strnglen) 533766Speter fmtspec = SKIP; 534766Speter else 535766Speter field -= strnglen; 536766Speter } 537766Speter break; 538766Speter default: 539766Speter error("Can't write %ss to a text file", clnames[typ]); 540766Speter continue; 541766Speter } 542766Speter /* 543766Speter * Generate the format string 544766Speter */ 545766Speter switch (fmtspec) { 546766Speter default: 547766Speter panic("fmt2"); 548766Speter case NIL: 549766Speter if (fmt == 'c') { 550766Speter if ( opt( 't' ) ) { 551766Speter putleaf( P2ICON , 0 , 0 552766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 553766Speter , "_WRITEC" ); 5543833Speter putRV( 0 , cbn , CURFILEOFFSET , 5553833Speter NLOCAL , P2PTR|P2STRTY ); 556766Speter stkrval( alv , NIL , RREQ ); 557766Speter putop( P2LISTOP , P2INT ); 558766Speter } else { 559766Speter putleaf( P2ICON , 0 , 0 560766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 561766Speter , "_fputc" ); 562766Speter stkrval( alv , NIL , RREQ ); 563766Speter } 564766Speter putleaf( P2ICON , 0 , 0 565766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 566766Speter , "_ACTFILE" ); 5673833Speter putRV( 0, cbn , CURFILEOFFSET , 5683833Speter NLOCAL , P2PTR|P2STRTY ); 569766Speter putop( P2CALL , P2INT ); 570766Speter putop( P2LISTOP , P2INT ); 571766Speter putop( P2CALL , P2INT ); 572766Speter putdot( filename , line ); 573766Speter } else { 574766Speter sprintf(&format[1], "%%%c", fmt); 575766Speter goto fmtgen; 576766Speter } 577766Speter case SKIP: 578766Speter break; 579766Speter case CONWIDTH: 580766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 581766Speter goto fmtgen; 582766Speter case VARWIDTH: 583766Speter sprintf(&format[1], "%%*%c", fmt); 584766Speter goto fmtgen; 585766Speter case CONWIDTH + CONPREC: 586766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 587766Speter goto fmtgen; 588766Speter case CONWIDTH + VARPREC: 589766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 590766Speter goto fmtgen; 591766Speter case VARWIDTH + CONPREC: 592766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 593766Speter goto fmtgen; 594766Speter case VARWIDTH + VARPREC: 595766Speter sprintf(&format[1], "%%*.*%c", fmt); 596766Speter fmtgen: 597766Speter if ( opt( 't' ) ) { 598766Speter putleaf( P2ICON , 0 , 0 599766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 600766Speter , "_WRITEF" ); 6013833Speter putRV( 0 , cbn , CURFILEOFFSET , 6023833Speter NLOCAL , P2PTR|P2STRTY ); 603766Speter putleaf( P2ICON , 0 , 0 604766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 605766Speter , "_ACTFILE" ); 6063833Speter putRV( 0 , cbn , CURFILEOFFSET , 6073833Speter NLOCAL , P2PTR|P2STRTY ); 608766Speter putop( P2CALL , P2INT ); 609766Speter putop( P2LISTOP , P2INT ); 610766Speter } else { 611766Speter putleaf( P2ICON , 0 , 0 612766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 613766Speter , "_fprintf" ); 614766Speter putleaf( P2ICON , 0 , 0 615766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 616766Speter , "_ACTFILE" ); 6173833Speter putRV( 0 , cbn , CURFILEOFFSET , 6183833Speter NLOCAL , P2PTR|P2STRTY ); 619766Speter putop( P2CALL , P2INT ); 620766Speter } 621766Speter putCONG( &format[ fmtstart ] 622766Speter , strlen( &format[ fmtstart ] ) 623766Speter , LREQ ); 624766Speter putop( P2LISTOP , P2INT ); 625766Speter if ( fmtspec & VARWIDTH ) { 626766Speter /* 627766Speter * either 628766Speter * ,(temp=width,MAX(temp,...)), 629766Speter * or 630766Speter * , MAX( width , ... ) , 631766Speter */ 632766Speter if ( ( typ == TDOUBLE && al[3] == NIL ) 633766Speter || typ == TSTR ) { 6343225Smckusic soffset = sizes[cbn].curtmps; 6353833Speter tempnlp = tmpalloc(sizeof(long), 6363225Smckusic nl+T4INT, REGOK); 6373833Speter putRV( 0 , cbn , 6383833Speter tempnlp -> value[ NL_OFFS ] , 6393833Speter tempnlp -> extra_flags , P2INT ); 640766Speter ap = stkrval( al[2] , NIL , RREQ ); 641766Speter putop( P2ASSIGN , P2INT ); 642766Speter putleaf( P2ICON , 0 , 0 643766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 644766Speter , "_MAX" ); 6453833Speter putRV( 0 , cbn , 6463833Speter tempnlp -> value[ NL_OFFS ] , 6473833Speter tempnlp -> extra_flags , P2INT ); 648766Speter } else { 649766Speter if (opt('t') 650766Speter || typ == TSTR || typ == TDOUBLE) { 651766Speter putleaf( P2ICON , 0 , 0 652766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 653766Speter ,"_MAX" ); 654766Speter } 655766Speter ap = stkrval( al[2] , NIL , RREQ ); 656766Speter } 657766Speter if (ap == NIL) 658766Speter continue; 659766Speter if (isnta(ap,"i")) { 660766Speter error("First write width must be integer, not %s", nameof(ap)); 661766Speter continue; 662766Speter } 663766Speter switch ( typ ) { 664766Speter case TDOUBLE: 6659229Smckusick putleaf( P2ICON , REALSPC , 0 , P2INT , 0 ); 666766Speter putop( P2LISTOP , P2INT ); 667766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 668766Speter putop( P2LISTOP , P2INT ); 669766Speter putop( P2CALL , P2INT ); 670766Speter if ( al[3] == NIL ) { 671766Speter /* 672766Speter * finish up the comma op 673766Speter */ 674766Speter putop( P2COMOP , P2INT ); 675766Speter fmtspec &= ~VARPREC; 676766Speter putop( P2LISTOP , P2INT ); 677766Speter putleaf( P2ICON , 0 , 0 678766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 679766Speter , "_MAX" ); 6803833Speter putRV( 0 , cbn , 6813833Speter tempnlp -> value[ NL_OFFS ] , 6823833Speter tempnlp -> extra_flags , 6833833Speter P2INT ); 6843225Smckusic tmpfree(&soffset); 6859229Smckusick putleaf( P2ICON , 7 + REALSPC , 0 , P2INT , 0 ); 686766Speter putop( P2LISTOP , P2INT ); 687766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 688766Speter putop( P2LISTOP , P2INT ); 689766Speter putop( P2CALL , P2INT ); 690766Speter } 691766Speter putop( P2LISTOP , P2INT ); 692766Speter break; 693766Speter case TSTR: 694766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 695766Speter putop( P2LISTOP , P2INT ); 696766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 697766Speter putop( P2LISTOP , P2INT ); 698766Speter putop( P2CALL , P2INT ); 699766Speter putop( P2COMOP , P2INT ); 700766Speter putop( P2LISTOP , P2INT ); 701766Speter break; 702766Speter default: 703766Speter if (opt('t')) { 704766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 705766Speter putop( P2LISTOP , P2INT ); 706766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 707766Speter putop( P2LISTOP , P2INT ); 708766Speter putop( P2CALL , P2INT ); 709766Speter } 710766Speter putop( P2LISTOP , P2INT ); 711766Speter break; 712766Speter } 713766Speter } 714766Speter /* 715766Speter * If there is a variable precision, 716766Speter * evaluate it 717766Speter */ 718766Speter if (fmtspec & VARPREC) { 719766Speter if (opt('t')) { 720766Speter putleaf( P2ICON , 0 , 0 721766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 722766Speter , "_MAX" ); 723766Speter } 724766Speter ap = stkrval( al[3] , NIL , RREQ ); 725766Speter if (ap == NIL) 726766Speter continue; 727766Speter if (isnta(ap,"i")) { 728766Speter error("Second write width must be integer, not %s", nameof(ap)); 729766Speter continue; 730766Speter } 731766Speter if (opt('t')) { 732766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 733766Speter putop( P2LISTOP , P2INT ); 734766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 735766Speter putop( P2LISTOP , P2INT ); 736766Speter putop( P2CALL , P2INT ); 737766Speter } 738766Speter putop( P2LISTOP , P2INT ); 739766Speter } 740766Speter /* 741766Speter * evaluate the thing we want printed. 742766Speter */ 743766Speter switch ( typ ) { 7446540Smckusick case TPTR: 745766Speter case TCHAR: 746766Speter case TINT: 747766Speter stkrval( alv , NIL , RREQ ); 748766Speter putop( P2LISTOP , P2INT ); 749766Speter break; 750766Speter case TDOUBLE: 751766Speter ap = stkrval( alv , NIL , RREQ ); 75210370Speter if ( isnta( ap , "d" ) ) { 75310370Speter putop( P2SCONV , P2DOUBLE ); 754766Speter } 755766Speter putop( P2LISTOP , P2INT ); 756766Speter break; 757766Speter case TSCAL: 758766Speter case TBOOL: 759766Speter putleaf( P2ICON , 0 , 0 760766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 761766Speter , "_NAM" ); 762766Speter ap = stkrval( alv , NIL , RREQ ); 763766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 764766Speter , listnames( ap ) ); 765766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 766766Speter , format ); 767766Speter putop( P2LISTOP , P2INT ); 768766Speter putop( P2CALL , P2INT ); 769766Speter putop( P2LISTOP , P2INT ); 770766Speter break; 771766Speter case TSTR: 772766Speter putCONG( "" , 0 , LREQ ); 773766Speter putop( P2LISTOP , P2INT ); 774766Speter break; 7756540Smckusick default: 7766540Smckusick panic("fmt3"); 7776540Smckusick break; 778766Speter } 779766Speter putop( P2CALL , P2INT ); 780766Speter putdot( filename , line ); 781766Speter } 782766Speter /* 783766Speter * Write the string after its blank padding 784766Speter */ 785766Speter if (typ == TSTR ) { 786766Speter if ( opt( 't' ) ) { 787766Speter putleaf( P2ICON , 0 , 0 788766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 789766Speter , "_WRITES" ); 7903833Speter putRV( 0 , cbn , CURFILEOFFSET , 7913833Speter NLOCAL , P2PTR|P2STRTY ); 792766Speter ap = stkrval(alv, NIL , RREQ ); 793766Speter putop( P2LISTOP , P2INT ); 794766Speter } else { 795766Speter putleaf( P2ICON , 0 , 0 796766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 797766Speter , "_fwrite" ); 798766Speter ap = stkrval(alv, NIL , RREQ ); 799766Speter } 800766Speter if (strfmt & VARWIDTH) { 801766Speter /* 802766Speter * min, inline expanded as 803766Speter * temp < len ? temp : len 804766Speter */ 8053833Speter putRV( 0 , cbn , 8063833Speter tempnlp -> value[ NL_OFFS ] , 8073833Speter tempnlp -> extra_flags , P2INT ); 808766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 809766Speter putop( P2LT , P2INT ); 8103833Speter putRV( 0 , cbn , 8113833Speter tempnlp -> value[ NL_OFFS ] , 8123833Speter tempnlp -> extra_flags , P2INT ); 813766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 814766Speter putop( P2COLON , P2INT ); 815766Speter putop( P2QUEST , P2INT ); 8163225Smckusic tmpfree(&soffset); 817766Speter } else { 818766Speter if ( ( fmtspec & SKIP ) 819766Speter && ( strfmt & CONWIDTH ) ) { 820766Speter strnglen = field; 821766Speter } 822766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 823766Speter } 824766Speter putop( P2LISTOP , P2INT ); 825766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 826766Speter putop( P2LISTOP , P2INT ); 827766Speter putleaf( P2ICON , 0 , 0 828766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 829766Speter , "_ACTFILE" ); 8303833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 8313833Speter P2PTR|P2STRTY ); 832766Speter putop( P2CALL , P2INT ); 833766Speter putop( P2LISTOP , P2INT ); 834766Speter putop( P2CALL , P2INT ); 835766Speter putdot( filename , line ); 836766Speter } 837766Speter } 838766Speter /* 839766Speter * Done with arguments. 840766Speter * Handle writeln and 841766Speter * insufficent number of args. 842766Speter */ 843766Speter switch (p->value[0] &~ NSTAND) { 844766Speter case O_WRITEF: 845766Speter if (argc == 0) 846766Speter error("Write requires an argument"); 847766Speter break; 848766Speter case O_MESSAGE: 849766Speter if (argc == 0) 850766Speter error("Message requires an argument"); 851766Speter case O_WRITLN: 852766Speter if (filetype != nl+T1CHAR) 853766Speter error("Can't 'writeln' a non text file"); 854766Speter if ( opt( 't' ) ) { 855766Speter putleaf( P2ICON , 0 , 0 856766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 857766Speter , "_WRITLN" ); 8583833Speter putRV( 0 , cbn , CURFILEOFFSET , 8593833Speter NLOCAL , P2PTR|P2STRTY ); 860766Speter } else { 861766Speter putleaf( P2ICON , 0 , 0 862766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 863766Speter , "_fputc" ); 864766Speter putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 ); 865766Speter putleaf( P2ICON , 0 , 0 866766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 867766Speter , "_ACTFILE" ); 8683833Speter putRV( 0 , cbn , CURFILEOFFSET , 8693833Speter NLOCAL , P2PTR|P2STRTY ); 870766Speter putop( P2CALL , P2INT ); 871766Speter putop( P2LISTOP , P2INT ); 872766Speter } 873766Speter putop( P2CALL , P2INT ); 874766Speter putdot( filename , line ); 875766Speter break; 876766Speter } 877766Speter return; 878766Speter 879766Speter case O_READ4: 880766Speter case O_READLN: 881766Speter /* 882766Speter * Set up default 883766Speter * file "input". 884766Speter */ 885766Speter file = NIL; 886766Speter filetype = nl+T1CHAR; 887766Speter /* 888766Speter * Determine the file implied 889766Speter * for the read and generate 890766Speter * code to make it the active file. 891766Speter */ 892766Speter if (argv != NIL) { 893766Speter codeoff(); 894766Speter ap = stkrval(argv[1], NIL , RREQ ); 895766Speter codeon(); 896766Speter if (ap == NIL) 897766Speter argv = argv[2]; 898766Speter if (ap != NIL && ap->class == FILET) { 899766Speter /* 900766Speter * Got "read(f, ...", make 901766Speter * f the active file, and save 902766Speter * it and its type for use in 903766Speter * processing the rest of the 904766Speter * arguments to read. 905766Speter */ 906766Speter file = argv[1]; 907766Speter filetype = ap->type; 9083833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9093833Speter P2PTR|P2STRTY ); 910766Speter putleaf( P2ICON , 0 , 0 911766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 912766Speter , "_UNIT" ); 913766Speter stklval(argv[1], NOFLAGS); 914766Speter putop( P2CALL , P2INT ); 915766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 916766Speter putdot( filename , line ); 917766Speter argv = argv[2]; 918766Speter argc--; 919766Speter } else { 920766Speter /* 921766Speter * Default is read from 922766Speter * standard input. 923766Speter */ 9243833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9253833Speter P2PTR|P2STRTY ); 9263833Speter putLV( "_input" , 0 , 0 , NGLOBAL , 9273833Speter P2PTR|P2STRTY ); 928766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 929766Speter putdot( filename , line ); 930766Speter input->nl_flags |= NUSED; 931766Speter } 932766Speter } else { 9333833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9343833Speter P2PTR|P2STRTY ); 9353833Speter putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 936766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 937766Speter putdot( filename , line ); 938766Speter input->nl_flags |= NUSED; 939766Speter } 940766Speter /* 941766Speter * Loop and process each 942766Speter * of the arguments. 943766Speter */ 944766Speter for (; argv != NIL; argv = argv[2]) { 945766Speter /* 946766Speter * Get the address of the target 947766Speter * on the stack. 948766Speter */ 949766Speter al = argv[1]; 950766Speter if (al == NIL) 951766Speter continue; 952766Speter if (al[0] != T_VAR) { 953766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 954766Speter continue; 955766Speter } 956766Speter codeoff(); 957766Speter ap = stklval(al, MOD|ASGN|NOUSE); 958766Speter codeon(); 959766Speter if (ap == NIL) 960766Speter continue; 961766Speter if (filetype != nl+T1CHAR) { 962766Speter /* 963766Speter * Generalized read, i.e. 964766Speter * from a non-textfile. 965766Speter */ 966766Speter if (incompat(filetype, ap, argv[1] )) { 967766Speter error("Type mismatch in read from non-text file"); 968766Speter continue; 969766Speter } 970766Speter /* 971766Speter * var := file ^; 972766Speter */ 973766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 974766Speter if ( isa( ap , "bsci" ) ) { 975766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 976766Speter } 977766Speter putleaf( P2ICON , 0 , 0 978766Speter , ADDTYPE( 979766Speter ADDTYPE( 980766Speter ADDTYPE( 981766Speter p2type( filetype ) , P2PTR ) 982766Speter , P2FTN ) 983766Speter , P2PTR ) 984766Speter , "_FNIL" ); 985766Speter if (file != NIL) 986766Speter stklval(file, NOFLAGS); 987766Speter else /* Magic */ 9883833Speter putRV( "_input" , 0 , 0 , NGLOBAL , 9893833Speter P2PTR | P2STRTY ); 990766Speter putop( P2CALL , P2INT ); 991766Speter switch ( classify( filetype ) ) { 992766Speter case TBOOL: 993766Speter case TCHAR: 994766Speter case TINT: 995766Speter case TSCAL: 996766Speter case TDOUBLE: 997766Speter case TPTR: 998766Speter putop( P2UNARY P2MUL 999766Speter , p2type( filetype ) ); 1000766Speter } 1001766Speter switch ( classify( filetype ) ) { 1002766Speter case TBOOL: 1003766Speter case TCHAR: 1004766Speter case TINT: 1005766Speter case TSCAL: 100610370Speter postcheck( ap ); 1007766Speter /* and fall through */ 1008766Speter case TDOUBLE: 1009766Speter case TPTR: 1010766Speter putop( P2ASSIGN , p2type( ap ) ); 1011766Speter putdot( filename , line ); 1012766Speter break; 1013766Speter default: 1014766Speter putstrop( P2STASG 1015766Speter , p2type( ap ) 1016766Speter , lwidth( ap ) 1017766Speter , align( ap ) ); 1018766Speter putdot( filename , line ); 1019766Speter break; 1020766Speter } 1021766Speter /* 1022766Speter * get(file); 1023766Speter */ 1024766Speter putleaf( P2ICON , 0 , 0 1025766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1026766Speter , "_GET" ); 10273833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10283833Speter P2PTR|P2STRTY ); 1029766Speter putop( P2CALL , P2INT ); 1030766Speter putdot( filename , line ); 1031766Speter continue; 1032766Speter } 1033766Speter /* 1034766Speter * if you get to here, you are reading from 1035766Speter * a text file. only possiblities are: 1036766Speter * character, integer, real, or scalar. 1037766Speter * read( f , foo , ... ) is done as 1038766Speter * foo := read( f ) with rangechecking 1039766Speter * if appropriate. 1040766Speter */ 1041766Speter typ = classify(ap); 1042766Speter op = rdops(typ); 1043766Speter if (op == NIL) { 1044766Speter error("Can't read %ss from a text file", clnames[typ]); 1045766Speter continue; 1046766Speter } 1047766Speter /* 1048766Speter * left hand side of foo := read( f ) 1049766Speter */ 1050766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 1051766Speter if ( isa( ap , "bsci" ) ) { 1052766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1053766Speter } 1054766Speter switch ( op ) { 1055766Speter case O_READC: 1056766Speter readname = "_READC"; 1057766Speter readtype = P2INT; 1058766Speter break; 1059766Speter case O_READ4: 1060766Speter readname = "_READ4"; 1061766Speter readtype = P2INT; 1062766Speter break; 1063766Speter case O_READ8: 1064766Speter readname = "_READ8"; 1065766Speter readtype = P2DOUBLE; 1066766Speter break; 1067766Speter case O_READE: 1068766Speter readname = "_READE"; 1069766Speter readtype = P2INT; 1070766Speter break; 1071766Speter } 1072766Speter putleaf( P2ICON , 0 , 0 1073766Speter , ADDTYPE( P2FTN | readtype , P2PTR ) 1074766Speter , readname ); 10753833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10763833Speter P2PTR|P2STRTY ); 1077766Speter if ( op == O_READE ) { 1078766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1079766Speter , listnames( ap ) ); 1080766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 1081766Speter , format ); 1082766Speter putop( P2LISTOP , P2INT ); 10831629Speter warning(); 1084766Speter if (opt('s')) { 1085766Speter standard(); 1086766Speter } 10871629Speter error("Reading scalars from text files is non-standard"); 1088766Speter } 1089766Speter putop( P2CALL , readtype ); 1090766Speter if ( isa( ap , "bcsi" ) ) { 109110370Speter postcheck( ap ); 1092766Speter } 1093766Speter putop( P2ASSIGN , p2type( ap ) ); 1094766Speter putdot( filename , line ); 1095766Speter } 1096766Speter /* 1097766Speter * Done with arguments. 1098766Speter * Handle readln and 1099766Speter * insufficient number of args. 1100766Speter */ 1101766Speter if (p->value[0] == O_READLN) { 1102766Speter if (filetype != nl+T1CHAR) 1103766Speter error("Can't 'readln' a non text file"); 1104766Speter putleaf( P2ICON , 0 , 0 1105766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1106766Speter , "_READLN" ); 11073833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 11083833Speter P2PTR|P2STRTY ); 1109766Speter putop( P2CALL , P2INT ); 1110766Speter putdot( filename , line ); 1111766Speter } else if (argc == 0) 1112766Speter error("read requires an argument"); 1113766Speter return; 1114766Speter 1115766Speter case O_GET: 1116766Speter case O_PUT: 1117766Speter if (argc != 1) { 1118766Speter error("%s expects one argument", p->symbol); 1119766Speter return; 1120766Speter } 11213833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1122766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1123766Speter , "_UNIT" ); 1124766Speter ap = stklval(argv[1], NOFLAGS); 1125766Speter if (ap == NIL) 1126766Speter return; 1127766Speter if (ap->class != FILET) { 1128766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1129766Speter return; 1130766Speter } 1131766Speter putop( P2CALL , P2INT ); 1132766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1133766Speter putdot( filename , line ); 1134766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1135766Speter , op == O_GET ? "_GET" : "_PUT" ); 11363833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1137766Speter putop( P2CALL , P2INT ); 1138766Speter putdot( filename , line ); 1139766Speter return; 1140766Speter 1141766Speter case O_RESET: 1142766Speter case O_REWRITE: 1143766Speter if (argc == 0 || argc > 2) { 1144766Speter error("%s expects one or two arguments", p->symbol); 1145766Speter return; 1146766Speter } 1147766Speter if (opt('s') && argc == 2) { 1148766Speter standard(); 1149766Speter error("Two argument forms of reset and rewrite are non-standard"); 1150766Speter } 1151766Speter putleaf( P2ICON , 0 , 0 , P2INT 1152766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 1153766Speter ap = stklval(argv[1], MOD|NOUSE); 1154766Speter if (ap == NIL) 1155766Speter return; 1156766Speter if (ap->class != FILET) { 1157766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1158766Speter return; 1159766Speter } 1160766Speter if (argc == 2) { 1161766Speter /* 1162766Speter * Optional second argument 1163766Speter * is a string name of a 1164766Speter * UNIX (R) file to be associated. 1165766Speter */ 1166766Speter al = argv[2]; 1167766Speter al = stkrval(al[1], NOFLAGS , RREQ ); 1168766Speter if (al == NIL) 1169766Speter return; 1170766Speter if (classify(al) != TSTR) { 1171766Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 1172766Speter return; 1173766Speter } 1174766Speter strnglen = width(al); 1175766Speter } else { 1176766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 1177766Speter strnglen = 0; 1178766Speter } 1179766Speter putop( P2LISTOP , P2INT ); 1180766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 1181766Speter putop( P2LISTOP , P2INT ); 1182766Speter putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 ); 1183766Speter putop( P2LISTOP , P2INT ); 1184766Speter putop( P2CALL , P2INT ); 1185766Speter putdot( filename , line ); 1186766Speter return; 1187766Speter 1188766Speter case O_NEW: 1189766Speter case O_DISPOSE: 1190766Speter if (argc == 0) { 1191766Speter error("%s expects at least one argument", p->symbol); 1192766Speter return; 1193766Speter } 11949139Smckusick alv = argv[1]; 11957967Smckusick codeoff(); 11969139Smckusick ap = stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 11977967Smckusick codeon(); 1198766Speter if (ap == NIL) 1199766Speter return; 1200766Speter if (ap->class != PTR) { 1201766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1202766Speter return; 1203766Speter } 1204766Speter ap = ap->type; 1205766Speter if (ap == NIL) 1206766Speter return; 12079139Smckusick if (op == O_NEW) 12089139Smckusick cmd = "_NEW"; 12099139Smckusick else /* op == O_DISPOSE */ 12107967Smckusick if ((ap->nl_flags & NFILES) != 0) 12117967Smckusick cmd = "_DFDISPOSE"; 12127967Smckusick else 12137967Smckusick cmd = "_DISPOSE"; 12147967Smckusick putleaf( P2ICON, 0, 0, ADDTYPE( P2FTN | P2INT , P2PTR ), cmd); 12159139Smckusick stklval(alv, op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1216766Speter argv = argv[2]; 1217766Speter if (argv != NIL) { 1218766Speter if (ap->class != RECORD) { 1219766Speter error("Record required when specifying variant tags"); 1220766Speter return; 1221766Speter } 1222766Speter for (; argv != NIL; argv = argv[2]) { 1223766Speter if (ap->ptr[NL_VARNT] == NIL) { 1224766Speter error("Too many tag fields"); 1225766Speter return; 1226766Speter } 1227766Speter if (!isconst(argv[1])) { 1228766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1229766Speter return; 1230766Speter } 1231766Speter gconst(argv[1]); 1232766Speter if (con.ctype == NIL) 1233766Speter return; 1234766Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 1235766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1236766Speter return; 1237766Speter } 1238766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1239766Speter if (ap->range[0] == con.crval) 1240766Speter break; 1241766Speter if (ap == NIL) { 1242766Speter error("No variant case label value equals specified constant value"); 1243766Speter return; 1244766Speter } 1245766Speter ap = ap->ptr[NL_VTOREC]; 1246766Speter } 1247766Speter } 1248766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1249766Speter putop( P2LISTOP , P2INT ); 1250766Speter putop( P2CALL , P2INT ); 1251766Speter putdot( filename , line ); 12529139Smckusick if (opt('t') && op == O_NEW) { 12539139Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 12549139Smckusick , "_blkclr" ); 12559264Smckusick stkrval(alv, NIL , RREQ ); 12569139Smckusick putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 12579139Smckusick putop( P2LISTOP , P2INT ); 12589139Smckusick putop( P2CALL , P2INT ); 12599139Smckusick putdot( filename , line ); 12609139Smckusick } 1261766Speter return; 1262766Speter 1263766Speter case O_DATE: 1264766Speter case O_TIME: 1265766Speter if (argc != 1) { 1266766Speter error("%s expects one argument", p->symbol); 1267766Speter return; 1268766Speter } 1269766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1270766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 1271766Speter ap = stklval(argv[1], MOD|NOUSE); 1272766Speter if (ap == NIL) 1273766Speter return; 1274766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1275766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1276766Speter return; 1277766Speter } 1278766Speter putop( P2CALL , P2INT ); 1279766Speter putdot( filename , line ); 1280766Speter return; 1281766Speter 1282766Speter case O_HALT: 1283766Speter if (argc != 0) { 1284766Speter error("halt takes no arguments"); 1285766Speter return; 1286766Speter } 1287766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1288766Speter , "_HALT" ); 1289766Speter 1290766Speter putop( P2UNARY P2CALL , P2INT ); 1291766Speter putdot( filename , line ); 1292766Speter noreach = 1; 1293766Speter return; 1294766Speter 1295766Speter case O_ARGV: 1296766Speter if (argc != 2) { 1297766Speter error("argv takes two arguments"); 1298766Speter return; 1299766Speter } 1300766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1301766Speter , "_ARGV" ); 1302766Speter ap = stkrval(argv[1], NIL , RREQ ); 1303766Speter if (ap == NIL) 1304766Speter return; 1305766Speter if (isnta(ap, "i")) { 1306766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1307766Speter return; 1308766Speter } 1309766Speter al = argv[2]; 1310766Speter ap = stklval(al[1], MOD|NOUSE); 1311766Speter if (ap == NIL) 1312766Speter return; 1313766Speter if (classify(ap) != TSTR) { 1314766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1315766Speter return; 1316766Speter } 1317766Speter putop( P2LISTOP , P2INT ); 1318766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1319766Speter putop( P2LISTOP , P2INT ); 1320766Speter putop( P2CALL , P2INT ); 1321766Speter putdot( filename , line ); 1322766Speter return; 1323766Speter 1324766Speter case O_STLIM: 1325766Speter if (argc != 1) { 1326766Speter error("stlimit requires one argument"); 1327766Speter return; 1328766Speter } 1329766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1330766Speter , "_STLIM" ); 1331766Speter ap = stkrval(argv[1], NIL , RREQ ); 1332766Speter if (ap == NIL) 1333766Speter return; 1334766Speter if (isnta(ap, "i")) { 1335766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1336766Speter return; 1337766Speter } 1338766Speter putop( P2CALL , P2INT ); 1339766Speter putdot( filename , line ); 1340766Speter return; 1341766Speter 1342766Speter case O_REMOVE: 1343766Speter if (argc != 1) { 1344766Speter error("remove expects one argument"); 1345766Speter return; 1346766Speter } 1347766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1348766Speter , "_REMOVE" ); 1349766Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 1350766Speter if (ap == NIL) 1351766Speter return; 1352766Speter if (classify(ap) != TSTR) { 1353766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1354766Speter return; 1355766Speter } 1356766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1357766Speter putop( P2LISTOP , P2INT ); 1358766Speter putop( P2CALL , P2INT ); 1359766Speter putdot( filename , line ); 1360766Speter return; 1361766Speter 1362766Speter case O_LLIMIT: 1363766Speter if (argc != 2) { 1364766Speter error("linelimit expects two arguments"); 1365766Speter return; 1366766Speter } 1367766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1368766Speter , "_LLIMIT" ); 1369766Speter ap = stklval(argv[1], NOFLAGS|NOUSE); 1370766Speter if (ap == NIL) 1371766Speter return; 1372766Speter if (!text(ap)) { 1373766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1374766Speter return; 1375766Speter } 1376766Speter al = argv[2]; 1377766Speter ap = stkrval(al[1], NIL , RREQ ); 1378766Speter if (ap == NIL) 1379766Speter return; 1380766Speter if (isnta(ap, "i")) { 1381766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1382766Speter return; 1383766Speter } 1384766Speter putop( P2LISTOP , P2INT ); 1385766Speter putop( P2CALL , P2INT ); 1386766Speter putdot( filename , line ); 1387766Speter return; 1388766Speter case O_PAGE: 1389766Speter if (argc != 1) { 1390766Speter error("page expects one argument"); 1391766Speter return; 1392766Speter } 13933833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1394766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1395766Speter , "_UNIT" ); 1396766Speter ap = stklval(argv[1], NOFLAGS); 1397766Speter if (ap == NIL) 1398766Speter return; 1399766Speter if (!text(ap)) { 1400766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1401766Speter return; 1402766Speter } 1403766Speter putop( P2CALL , P2INT ); 1404766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1405766Speter putdot( filename , line ); 1406766Speter if ( opt( 't' ) ) { 1407766Speter putleaf( P2ICON , 0 , 0 1408766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1409766Speter , "_PAGE" ); 14103833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1411766Speter } else { 1412766Speter putleaf( P2ICON , 0 , 0 1413766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1414766Speter , "_fputc" ); 1415766Speter putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 ); 1416766Speter putleaf( P2ICON , 0 , 0 1417766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1418766Speter , "_ACTFILE" ); 14193833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1420766Speter putop( P2CALL , P2INT ); 1421766Speter putop( P2LISTOP , P2INT ); 1422766Speter } 1423766Speter putop( P2CALL , P2INT ); 1424766Speter putdot( filename , line ); 1425766Speter return; 1426766Speter 14277928Smckusick case O_ASRT: 14287928Smckusick if (!opt('t')) 14297928Smckusick return; 14307928Smckusick if (argc == 0 || argc > 2) { 14317928Smckusick error("Assert expects one or two arguments"); 14327928Smckusick return; 14337928Smckusick } 14349139Smckusick if (argc == 2) 14359139Smckusick cmd = "_ASRTS"; 14369139Smckusick else 14379139Smckusick cmd = "_ASRT"; 14387928Smckusick putleaf( P2ICON , 0 , 0 14399139Smckusick , ADDTYPE( P2FTN | P2INT , P2PTR ) , cmd ); 14407928Smckusick ap = stkrval(argv[1], NIL , RREQ ); 14417928Smckusick if (ap == NIL) 14427928Smckusick return; 14437928Smckusick if (isnta(ap, "b")) 14447928Smckusick error("Assert expression must be Boolean, not %ss", nameof(ap)); 14457928Smckusick if (argc == 2) { 14467928Smckusick /* 14477928Smckusick * Optional second argument is a string specifying 14487928Smckusick * why the assertion failed. 14497928Smckusick */ 14507928Smckusick al = argv[2]; 14517928Smckusick al = stkrval(al[1], NIL , RREQ ); 14527928Smckusick if (al == NIL) 14537928Smckusick return; 14547928Smckusick if (classify(al) != TSTR) { 14557928Smckusick error("Second argument to assert must be a string, not %s", nameof(al)); 14567928Smckusick return; 14577928Smckusick } 14589139Smckusick putop( P2LISTOP , P2INT ); 14597928Smckusick } 14607928Smckusick putop( P2CALL , P2INT ); 14617928Smckusick putdot( filename , line ); 14627928Smckusick return; 14637928Smckusick 1464766Speter case O_PACK: 1465766Speter if (argc != 3) { 1466766Speter error("pack expects three arguments"); 1467766Speter return; 1468766Speter } 1469766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1470766Speter , "_PACK" ); 1471766Speter pu = "pack(a,i,z)"; 1472766Speter pua = (al = argv)[1]; 1473766Speter pui = (al = al[2])[1]; 1474766Speter puz = (al = al[2])[1]; 1475766Speter goto packunp; 1476766Speter case O_UNPACK: 1477766Speter if (argc != 3) { 1478766Speter error("unpack expects three arguments"); 1479766Speter return; 1480766Speter } 1481766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1482766Speter , "_UNPACK" ); 1483766Speter pu = "unpack(z,a,i)"; 1484766Speter puz = (al = argv)[1]; 1485766Speter pua = (al = al[2])[1]; 1486766Speter pui = (al = al[2])[1]; 1487766Speter packunp: 1488766Speter ap = stkrval((int *) pui, NLNIL , RREQ ); 1489766Speter if (ap == NIL) 1490766Speter return; 1491766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1492766Speter if (ap == NIL) 1493766Speter return; 1494766Speter if (ap->class != ARRAY) { 1495766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1496766Speter return; 1497766Speter } 1498766Speter putop( P2LISTOP , P2INT ); 1499766Speter al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1500766Speter if (al->class != ARRAY) { 1501766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1502766Speter return; 1503766Speter } 1504766Speter if (al->type == NIL || ap->type == NIL) 1505766Speter return; 1506766Speter if (al->type != ap->type) { 1507766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1508766Speter return; 1509766Speter } 1510766Speter putop( P2LISTOP , P2INT ); 1511766Speter k = width(al); 1512766Speter itemwidth = width(ap->type); 1513766Speter ap = ap->chain; 1514766Speter al = al->chain; 1515766Speter if (ap->chain != NIL || al->chain != NIL) { 1516766Speter error("%s requires a and z to be single dimension arrays", pu); 1517766Speter return; 1518766Speter } 1519766Speter if (ap == NIL || al == NIL) 1520766Speter return; 1521766Speter /* 1522766Speter * al is the range for z i.e. u..v 1523766Speter * ap is the range for a i.e. m..n 1524766Speter * i will be n-m+1 1525766Speter * j will be v-u+1 1526766Speter */ 1527766Speter i = ap->range[1] - ap->range[0] + 1; 1528766Speter j = al->range[1] - al->range[0] + 1; 1529766Speter if (i < j) { 1530766Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1531766Speter return; 1532766Speter } 1533766Speter /* 1534766Speter * get n-m-(v-u) and m for the interpreter 1535766Speter */ 1536766Speter i -= j; 1537766Speter j = ap->range[0]; 1538766Speter putleaf( P2ICON , itemwidth , 0 , P2INT , 0 ); 1539766Speter putop( P2LISTOP , P2INT ); 1540766Speter putleaf( P2ICON , j , 0 , P2INT , 0 ); 1541766Speter putop( P2LISTOP , P2INT ); 1542766Speter putleaf( P2ICON , i , 0 , P2INT , 0 ); 1543766Speter putop( P2LISTOP , P2INT ); 1544766Speter putleaf( P2ICON , k , 0 , P2INT , 0 ); 1545766Speter putop( P2LISTOP , P2INT ); 1546766Speter putop( P2CALL , P2INT ); 1547766Speter putdot( filename , line ); 1548766Speter return; 1549766Speter case 0: 15507928Smckusick error("%s is an unimplemented extension", p->symbol); 1551766Speter return; 1552766Speter 1553766Speter default: 1554766Speter panic("proc case"); 1555766Speter } 1556766Speter } 1557766Speter #endif PC 1558