1766Speter /* Copyright (c) 1979 Regents of the University of California */ 2766Speter 3*6540Smckusick static char sccsid[] = "@(#)pcproc.c 1.8 04/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; 50766Speter char fmt, format[20], *strptr; 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 ); 216766Speter } 217766Speter } else { 2183833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 2193833Speter P2PTR|P2STRTY ); 2203833Speter putLV( "_output" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 221766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 222766Speter putdot( filename , line ); 223766Speter } 224766Speter /* 225766Speter * Loop and process each 226766Speter * of the arguments. 227766Speter */ 228766Speter for (; argv != NIL; argv = argv[2]) { 229766Speter /* 230766Speter * fmtspec indicates the type (CONstant or VARiable) 231766Speter * and number (none, WIDTH, and/or PRECision) 232766Speter * of the fields in the printf format for this 233766Speter * output variable. 234766Speter * stkcnt is the number of longs pushed on the stack 235766Speter * fmt is the format output indicator (D, E, F, O, X, S) 236766Speter * fmtstart = 0 for leading blank; = 1 for no blank 237766Speter */ 238766Speter fmtspec = NIL; 239766Speter stkcnt = 0; 240766Speter fmt = 'D'; 241766Speter fmtstart = 1; 242766Speter al = argv[1]; 243766Speter if (al == NIL) 244766Speter continue; 245766Speter if (al[0] == T_WEXP) 246766Speter alv = al[1]; 247766Speter else 248766Speter alv = al; 249766Speter if (alv == NIL) 250766Speter continue; 251766Speter codeoff(); 252766Speter ap = stkrval(alv, NIL , RREQ ); 253766Speter codeon(); 254766Speter if (ap == NIL) 255766Speter continue; 256766Speter typ = classify(ap); 257766Speter if (al[0] == T_WEXP) { 258766Speter /* 259766Speter * Handle width expressions. 260766Speter * The basic game here is that width 261766Speter * expressions get evaluated. If they 262766Speter * are constant, the value is placed 263766Speter * directly in the format string. 264766Speter * Otherwise the value is pushed onto 265766Speter * the stack and an indirection is 266766Speter * put into the format string. 267766Speter */ 268766Speter if (al[3] == OCT) 269766Speter fmt = 'O'; 270766Speter else if (al[3] == HEX) 271766Speter fmt = 'X'; 272766Speter else if (al[3] != NIL) { 273766Speter /* 274766Speter * Evaluate second format spec 275766Speter */ 276766Speter if ( constval(al[3]) 277766Speter && isa( con.ctype , "i" ) ) { 278766Speter fmtspec += CONPREC; 279766Speter prec = con.crval; 280766Speter } else { 281766Speter fmtspec += VARPREC; 282766Speter } 283766Speter fmt = 'f'; 284766Speter switch ( typ ) { 285766Speter case TINT: 286766Speter if ( opt( 's' ) ) { 287766Speter standard(); 288766Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 289766Speter } 290766Speter /* and fall through */ 291766Speter case TDOUBLE: 292766Speter break; 293766Speter default: 294766Speter error("Cannot write %ss with two write widths", clnames[typ]); 295766Speter continue; 296766Speter } 297766Speter } 298766Speter /* 299766Speter * Evaluate first format spec 300766Speter */ 301766Speter if (al[2] != NIL) { 302766Speter if ( constval(al[2]) 303766Speter && isa( con.ctype , "i" ) ) { 304766Speter fmtspec += CONWIDTH; 305766Speter field = con.crval; 306766Speter } else { 307766Speter fmtspec += VARWIDTH; 308766Speter } 309766Speter } 310766Speter if ((fmtspec & CONPREC) && prec < 0 || 311766Speter (fmtspec & CONWIDTH) && field < 0) { 312766Speter error("Negative widths are not allowed"); 313766Speter continue; 314766Speter } 3153180Smckusic if ( opt('s') && 3163180Smckusic ((fmtspec & CONPREC) && prec == 0 || 3173180Smckusic (fmtspec & CONWIDTH) && field == 0)) { 3183180Smckusic standard(); 3193180Smckusic error("Zero widths are non-standard"); 3203180Smckusic } 321766Speter } 322766Speter if (filetype != nl+T1CHAR) { 323766Speter if (fmt == 'O' || fmt == 'X') { 324766Speter error("Oct/hex allowed only on text files"); 325766Speter continue; 326766Speter } 327766Speter if (fmtspec) { 328766Speter error("Write widths allowed only on text files"); 329766Speter continue; 330766Speter } 331766Speter /* 332766Speter * Generalized write, i.e. 333766Speter * to a non-textfile. 334766Speter */ 335766Speter putleaf( P2ICON , 0 , 0 336766Speter , ADDTYPE( 337766Speter ADDTYPE( 338766Speter ADDTYPE( p2type( filetype ) 339766Speter , P2PTR ) 340766Speter , P2FTN ) 341766Speter , P2PTR ) 342766Speter , "_FNIL" ); 343766Speter stklval(file, NOFLAGS); 344766Speter putop( P2CALL 345766Speter , ADDTYPE( p2type( filetype ) , P2PTR ) ); 346766Speter putop( P2UNARY P2MUL , p2type( filetype ) ); 347766Speter /* 348766Speter * file^ := ... 349766Speter */ 350766Speter switch ( classify( filetype ) ) { 351766Speter case TBOOL: 352766Speter case TCHAR: 353766Speter case TINT: 354766Speter case TSCAL: 3554589Speter precheck( filetype , "_RANG4" , "_RSNG4" ); 356766Speter /* and fall through */ 357766Speter case TDOUBLE: 358766Speter case TPTR: 359766Speter ap = rvalue( argv[1] , filetype , RREQ ); 360766Speter break; 361766Speter default: 362766Speter ap = rvalue( argv[1] , filetype , LREQ ); 363766Speter break; 364766Speter } 365766Speter if (ap == NIL) 366766Speter continue; 367766Speter if (incompat(ap, filetype, argv[1])) { 368766Speter cerror("Type mismatch in write to non-text file"); 369766Speter continue; 370766Speter } 371766Speter switch ( classify( filetype ) ) { 372766Speter case TBOOL: 373766Speter case TCHAR: 374766Speter case TINT: 375766Speter case TSCAL: 376766Speter postcheck( filetype ); 377766Speter /* and fall through */ 378766Speter case TDOUBLE: 379766Speter case TPTR: 380766Speter putop( P2ASSIGN , p2type( filetype ) ); 381766Speter putdot( filename , line ); 382766Speter break; 383766Speter default: 384766Speter putstrop( P2STASG 385766Speter , p2type( filetype ) 386766Speter , lwidth( filetype ) 387766Speter , align( filetype ) ); 388766Speter putdot( filename , line ); 389766Speter break; 390766Speter } 391766Speter /* 392766Speter * put(file) 393766Speter */ 394766Speter putleaf( P2ICON , 0 , 0 395766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 396766Speter , "_PUT" ); 3973833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 3983833Speter P2PTR|P2STRTY ); 399766Speter putop( P2CALL , P2INT ); 400766Speter putdot( filename , line ); 401766Speter continue; 402766Speter } 403766Speter /* 404766Speter * Write to a textfile 405766Speter * 406766Speter * Evaluate the expression 407766Speter * to be written. 408766Speter */ 409766Speter if (fmt == 'O' || fmt == 'X') { 410766Speter if (opt('s')) { 411766Speter standard(); 412766Speter error("Oct and hex are non-standard"); 413766Speter } 414766Speter if (typ == TSTR || typ == TDOUBLE) { 415766Speter error("Can't write %ss with oct/hex", clnames[typ]); 416766Speter continue; 417766Speter } 418766Speter if (typ == TCHAR || typ == TBOOL) 419766Speter typ = TINT; 420766Speter } 421766Speter /* 422766Speter * If there is no format specified by the programmer, 423766Speter * implement the default. 424766Speter */ 425766Speter switch (typ) { 426*6540Smckusick case TPTR: 427*6540Smckusick warning(); 428*6540Smckusick if (opt('s')) { 429*6540Smckusick standard(); 430*6540Smckusick } 431*6540Smckusick error("Writing %ss to text files is non-standard", 432*6540Smckusick clnames[typ]); 433*6540Smckusick /* and fall through */ 434766Speter case TINT: 435766Speter if (fmt == 'f') { 436766Speter typ = TDOUBLE; 437766Speter goto tdouble; 438766Speter } 439766Speter if (fmtspec == NIL) { 440766Speter if (fmt == 'D') 441766Speter field = 10; 442766Speter else if (fmt == 'X') 443766Speter field = 8; 444766Speter else if (fmt == 'O') 445766Speter field = 11; 446766Speter else 447766Speter panic("fmt1"); 448766Speter fmtspec = CONWIDTH; 449766Speter } 450766Speter break; 451766Speter case TCHAR: 452766Speter tchar: 453766Speter fmt = 'c'; 454766Speter break; 455766Speter case TSCAL: 4561629Speter warning(); 457766Speter if (opt('s')) { 458766Speter standard(); 459766Speter } 460*6540Smckusick error("Writing %ss to text files is non-standard", 461*6540Smckusick clnames[typ]); 462766Speter case TBOOL: 463766Speter fmt = 's'; 464766Speter break; 465766Speter case TDOUBLE: 466766Speter tdouble: 467766Speter switch (fmtspec) { 468766Speter case NIL: 469766Speter field = 21; 470766Speter prec = 14; 4713225Smckusic fmt = 'e'; 472766Speter fmtspec = CONWIDTH + CONPREC; 473766Speter break; 474766Speter case CONWIDTH: 475766Speter if (--field < 1) 476766Speter field = 1; 477766Speter prec = field - 7; 478766Speter if (prec < 1) 479766Speter prec = 1; 480766Speter fmtspec += CONPREC; 4813225Smckusic fmt = 'e'; 482766Speter break; 483766Speter case VARWIDTH: 484766Speter fmtspec += VARPREC; 4853225Smckusic fmt = 'e'; 486766Speter break; 487766Speter case CONWIDTH + CONPREC: 488766Speter case CONWIDTH + VARPREC: 489766Speter if (--field < 1) 490766Speter field = 1; 491766Speter } 492766Speter format[0] = ' '; 493766Speter fmtstart = 0; 494766Speter break; 495766Speter case TSTR: 496766Speter constval( alv ); 497766Speter switch ( classify( con.ctype ) ) { 498766Speter case TCHAR: 499766Speter typ = TCHAR; 500766Speter goto tchar; 501766Speter case TSTR: 502766Speter strptr = con.cpval; 503766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 504766Speter strptr = con.cpval; 505766Speter break; 506766Speter default: 507766Speter strnglen = width(ap); 508766Speter break; 509766Speter } 510766Speter fmt = 's'; 511766Speter strfmt = fmtspec; 512766Speter if (fmtspec == NIL) { 513766Speter fmtspec = SKIP; 514766Speter break; 515766Speter } 516766Speter if (fmtspec & CONWIDTH) { 517766Speter if (field <= strnglen) 518766Speter fmtspec = SKIP; 519766Speter else 520766Speter field -= strnglen; 521766Speter } 522766Speter break; 523766Speter default: 524766Speter error("Can't write %ss to a text file", clnames[typ]); 525766Speter continue; 526766Speter } 527766Speter /* 528766Speter * Generate the format string 529766Speter */ 530766Speter switch (fmtspec) { 531766Speter default: 532766Speter panic("fmt2"); 533766Speter case NIL: 534766Speter if (fmt == 'c') { 535766Speter if ( opt( 't' ) ) { 536766Speter putleaf( P2ICON , 0 , 0 537766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 538766Speter , "_WRITEC" ); 5393833Speter putRV( 0 , cbn , CURFILEOFFSET , 5403833Speter NLOCAL , P2PTR|P2STRTY ); 541766Speter stkrval( alv , NIL , RREQ ); 542766Speter putop( P2LISTOP , P2INT ); 543766Speter } else { 544766Speter putleaf( P2ICON , 0 , 0 545766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 546766Speter , "_fputc" ); 547766Speter stkrval( alv , NIL , RREQ ); 548766Speter } 549766Speter putleaf( P2ICON , 0 , 0 550766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 551766Speter , "_ACTFILE" ); 5523833Speter putRV( 0, cbn , CURFILEOFFSET , 5533833Speter NLOCAL , P2PTR|P2STRTY ); 554766Speter putop( P2CALL , P2INT ); 555766Speter putop( P2LISTOP , P2INT ); 556766Speter putop( P2CALL , P2INT ); 557766Speter putdot( filename , line ); 558766Speter } else { 559766Speter sprintf(&format[1], "%%%c", fmt); 560766Speter goto fmtgen; 561766Speter } 562766Speter case SKIP: 563766Speter break; 564766Speter case CONWIDTH: 565766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 566766Speter goto fmtgen; 567766Speter case VARWIDTH: 568766Speter sprintf(&format[1], "%%*%c", fmt); 569766Speter goto fmtgen; 570766Speter case CONWIDTH + CONPREC: 571766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 572766Speter goto fmtgen; 573766Speter case CONWIDTH + VARPREC: 574766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 575766Speter goto fmtgen; 576766Speter case VARWIDTH + CONPREC: 577766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 578766Speter goto fmtgen; 579766Speter case VARWIDTH + VARPREC: 580766Speter sprintf(&format[1], "%%*.*%c", fmt); 581766Speter fmtgen: 582766Speter if ( opt( 't' ) ) { 583766Speter putleaf( P2ICON , 0 , 0 584766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 585766Speter , "_WRITEF" ); 5863833Speter putRV( 0 , cbn , CURFILEOFFSET , 5873833Speter NLOCAL , P2PTR|P2STRTY ); 588766Speter putleaf( P2ICON , 0 , 0 589766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 590766Speter , "_ACTFILE" ); 5913833Speter putRV( 0 , cbn , CURFILEOFFSET , 5923833Speter NLOCAL , P2PTR|P2STRTY ); 593766Speter putop( P2CALL , P2INT ); 594766Speter putop( P2LISTOP , P2INT ); 595766Speter } else { 596766Speter putleaf( P2ICON , 0 , 0 597766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 598766Speter , "_fprintf" ); 599766Speter putleaf( P2ICON , 0 , 0 600766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 601766Speter , "_ACTFILE" ); 6023833Speter putRV( 0 , cbn , CURFILEOFFSET , 6033833Speter NLOCAL , P2PTR|P2STRTY ); 604766Speter putop( P2CALL , P2INT ); 605766Speter } 606766Speter putCONG( &format[ fmtstart ] 607766Speter , strlen( &format[ fmtstart ] ) 608766Speter , LREQ ); 609766Speter putop( P2LISTOP , P2INT ); 610766Speter if ( fmtspec & VARWIDTH ) { 611766Speter /* 612766Speter * either 613766Speter * ,(temp=width,MAX(temp,...)), 614766Speter * or 615766Speter * , MAX( width , ... ) , 616766Speter */ 617766Speter if ( ( typ == TDOUBLE && al[3] == NIL ) 618766Speter || typ == TSTR ) { 6193225Smckusic soffset = sizes[cbn].curtmps; 6203833Speter tempnlp = tmpalloc(sizeof(long), 6213225Smckusic nl+T4INT, REGOK); 6223833Speter putRV( 0 , cbn , 6233833Speter tempnlp -> value[ NL_OFFS ] , 6243833Speter tempnlp -> extra_flags , P2INT ); 625766Speter ap = stkrval( al[2] , NIL , RREQ ); 626766Speter putop( P2ASSIGN , P2INT ); 627766Speter putleaf( P2ICON , 0 , 0 628766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 629766Speter , "_MAX" ); 6303833Speter putRV( 0 , cbn , 6313833Speter tempnlp -> value[ NL_OFFS ] , 6323833Speter tempnlp -> extra_flags , P2INT ); 633766Speter } else { 634766Speter if (opt('t') 635766Speter || typ == TSTR || typ == TDOUBLE) { 636766Speter putleaf( P2ICON , 0 , 0 637766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 638766Speter ,"_MAX" ); 639766Speter } 640766Speter ap = stkrval( al[2] , NIL , RREQ ); 641766Speter } 642766Speter if (ap == NIL) 643766Speter continue; 644766Speter if (isnta(ap,"i")) { 645766Speter error("First write width must be integer, not %s", nameof(ap)); 646766Speter continue; 647766Speter } 648766Speter switch ( typ ) { 649766Speter case TDOUBLE: 650766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 651766Speter putop( P2LISTOP , P2INT ); 652766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 653766Speter putop( P2LISTOP , P2INT ); 654766Speter putop( P2CALL , P2INT ); 655766Speter if ( al[3] == NIL ) { 656766Speter /* 657766Speter * finish up the comma op 658766Speter */ 659766Speter putop( P2COMOP , P2INT ); 660766Speter fmtspec &= ~VARPREC; 661766Speter putop( P2LISTOP , P2INT ); 662766Speter putleaf( P2ICON , 0 , 0 663766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 664766Speter , "_MAX" ); 6653833Speter putRV( 0 , cbn , 6663833Speter tempnlp -> value[ NL_OFFS ] , 6673833Speter tempnlp -> extra_flags , 6683833Speter P2INT ); 6693225Smckusic tmpfree(&soffset); 670766Speter putleaf( P2ICON , 8 , 0 , P2INT , 0 ); 671766Speter putop( P2LISTOP , P2INT ); 672766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 673766Speter putop( P2LISTOP , P2INT ); 674766Speter putop( P2CALL , P2INT ); 675766Speter } 676766Speter putop( P2LISTOP , P2INT ); 677766Speter break; 678766Speter case TSTR: 679766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 680766Speter putop( P2LISTOP , P2INT ); 681766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 682766Speter putop( P2LISTOP , P2INT ); 683766Speter putop( P2CALL , P2INT ); 684766Speter putop( P2COMOP , P2INT ); 685766Speter putop( P2LISTOP , P2INT ); 686766Speter break; 687766Speter default: 688766Speter if (opt('t')) { 689766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 690766Speter putop( P2LISTOP , P2INT ); 691766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 692766Speter putop( P2LISTOP , P2INT ); 693766Speter putop( P2CALL , P2INT ); 694766Speter } 695766Speter putop( P2LISTOP , P2INT ); 696766Speter break; 697766Speter } 698766Speter } 699766Speter /* 700766Speter * If there is a variable precision, 701766Speter * evaluate it 702766Speter */ 703766Speter if (fmtspec & VARPREC) { 704766Speter if (opt('t')) { 705766Speter putleaf( P2ICON , 0 , 0 706766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 707766Speter , "_MAX" ); 708766Speter } 709766Speter ap = stkrval( al[3] , NIL , RREQ ); 710766Speter if (ap == NIL) 711766Speter continue; 712766Speter if (isnta(ap,"i")) { 713766Speter error("Second write width must be integer, not %s", nameof(ap)); 714766Speter continue; 715766Speter } 716766Speter if (opt('t')) { 717766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 718766Speter putop( P2LISTOP , P2INT ); 719766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 720766Speter putop( P2LISTOP , P2INT ); 721766Speter putop( P2CALL , P2INT ); 722766Speter } 723766Speter putop( P2LISTOP , P2INT ); 724766Speter } 725766Speter /* 726766Speter * evaluate the thing we want printed. 727766Speter */ 728766Speter switch ( typ ) { 729*6540Smckusick case TPTR: 730766Speter case TCHAR: 731766Speter case TINT: 732766Speter stkrval( alv , NIL , RREQ ); 733766Speter putop( P2LISTOP , P2INT ); 734766Speter break; 735766Speter case TDOUBLE: 736766Speter ap = stkrval( alv , NIL , RREQ ); 737766Speter if ( isnta( ap , "d" ) ) { 738766Speter putop( P2SCONV , P2DOUBLE ); 739766Speter } 740766Speter putop( P2LISTOP , P2INT ); 741766Speter break; 742766Speter case TSCAL: 743766Speter case TBOOL: 744766Speter putleaf( P2ICON , 0 , 0 745766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 746766Speter , "_NAM" ); 747766Speter ap = stkrval( alv , NIL , RREQ ); 748766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 749766Speter , listnames( ap ) ); 750766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 751766Speter , format ); 752766Speter putop( P2LISTOP , P2INT ); 753766Speter putop( P2CALL , P2INT ); 754766Speter putop( P2LISTOP , P2INT ); 755766Speter break; 756766Speter case TSTR: 757766Speter putCONG( "" , 0 , LREQ ); 758766Speter putop( P2LISTOP , P2INT ); 759766Speter break; 760*6540Smckusick default: 761*6540Smckusick panic("fmt3"); 762*6540Smckusick break; 763766Speter } 764766Speter putop( P2CALL , P2INT ); 765766Speter putdot( filename , line ); 766766Speter } 767766Speter /* 768766Speter * Write the string after its blank padding 769766Speter */ 770766Speter if (typ == TSTR ) { 771766Speter if ( opt( 't' ) ) { 772766Speter putleaf( P2ICON , 0 , 0 773766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 774766Speter , "_WRITES" ); 7753833Speter putRV( 0 , cbn , CURFILEOFFSET , 7763833Speter NLOCAL , P2PTR|P2STRTY ); 777766Speter ap = stkrval(alv, NIL , RREQ ); 778766Speter putop( P2LISTOP , P2INT ); 779766Speter } else { 780766Speter putleaf( P2ICON , 0 , 0 781766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 782766Speter , "_fwrite" ); 783766Speter ap = stkrval(alv, NIL , RREQ ); 784766Speter } 785766Speter if (strfmt & VARWIDTH) { 786766Speter /* 787766Speter * min, inline expanded as 788766Speter * temp < len ? temp : len 789766Speter */ 7903833Speter putRV( 0 , cbn , 7913833Speter tempnlp -> value[ NL_OFFS ] , 7923833Speter tempnlp -> extra_flags , P2INT ); 793766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 794766Speter putop( P2LT , P2INT ); 7953833Speter putRV( 0 , cbn , 7963833Speter tempnlp -> value[ NL_OFFS ] , 7973833Speter tempnlp -> extra_flags , P2INT ); 798766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 799766Speter putop( P2COLON , P2INT ); 800766Speter putop( P2QUEST , P2INT ); 8013225Smckusic tmpfree(&soffset); 802766Speter } else { 803766Speter if ( ( fmtspec & SKIP ) 804766Speter && ( strfmt & CONWIDTH ) ) { 805766Speter strnglen = field; 806766Speter } 807766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 808766Speter } 809766Speter putop( P2LISTOP , P2INT ); 810766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 811766Speter putop( P2LISTOP , P2INT ); 812766Speter putleaf( P2ICON , 0 , 0 813766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 814766Speter , "_ACTFILE" ); 8153833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 8163833Speter P2PTR|P2STRTY ); 817766Speter putop( P2CALL , P2INT ); 818766Speter putop( P2LISTOP , P2INT ); 819766Speter putop( P2CALL , P2INT ); 820766Speter putdot( filename , line ); 821766Speter } 822766Speter } 823766Speter /* 824766Speter * Done with arguments. 825766Speter * Handle writeln and 826766Speter * insufficent number of args. 827766Speter */ 828766Speter switch (p->value[0] &~ NSTAND) { 829766Speter case O_WRITEF: 830766Speter if (argc == 0) 831766Speter error("Write requires an argument"); 832766Speter break; 833766Speter case O_MESSAGE: 834766Speter if (argc == 0) 835766Speter error("Message requires an argument"); 836766Speter case O_WRITLN: 837766Speter if (filetype != nl+T1CHAR) 838766Speter error("Can't 'writeln' a non text file"); 839766Speter if ( opt( 't' ) ) { 840766Speter putleaf( P2ICON , 0 , 0 841766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 842766Speter , "_WRITLN" ); 8433833Speter putRV( 0 , cbn , CURFILEOFFSET , 8443833Speter NLOCAL , P2PTR|P2STRTY ); 845766Speter } else { 846766Speter putleaf( P2ICON , 0 , 0 847766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 848766Speter , "_fputc" ); 849766Speter putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 ); 850766Speter putleaf( P2ICON , 0 , 0 851766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 852766Speter , "_ACTFILE" ); 8533833Speter putRV( 0 , cbn , CURFILEOFFSET , 8543833Speter NLOCAL , P2PTR|P2STRTY ); 855766Speter putop( P2CALL , P2INT ); 856766Speter putop( P2LISTOP , P2INT ); 857766Speter } 858766Speter putop( P2CALL , P2INT ); 859766Speter putdot( filename , line ); 860766Speter break; 861766Speter } 862766Speter return; 863766Speter 864766Speter case O_READ4: 865766Speter case O_READLN: 866766Speter /* 867766Speter * Set up default 868766Speter * file "input". 869766Speter */ 870766Speter file = NIL; 871766Speter filetype = nl+T1CHAR; 872766Speter /* 873766Speter * Determine the file implied 874766Speter * for the read and generate 875766Speter * code to make it the active file. 876766Speter */ 877766Speter if (argv != NIL) { 878766Speter codeoff(); 879766Speter ap = stkrval(argv[1], NIL , RREQ ); 880766Speter codeon(); 881766Speter if (ap == NIL) 882766Speter argv = argv[2]; 883766Speter if (ap != NIL && ap->class == FILET) { 884766Speter /* 885766Speter * Got "read(f, ...", make 886766Speter * f the active file, and save 887766Speter * it and its type for use in 888766Speter * processing the rest of the 889766Speter * arguments to read. 890766Speter */ 891766Speter file = argv[1]; 892766Speter filetype = ap->type; 8933833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 8943833Speter P2PTR|P2STRTY ); 895766Speter putleaf( P2ICON , 0 , 0 896766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 897766Speter , "_UNIT" ); 898766Speter stklval(argv[1], NOFLAGS); 899766Speter putop( P2CALL , P2INT ); 900766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 901766Speter putdot( filename , line ); 902766Speter argv = argv[2]; 903766Speter argc--; 904766Speter } else { 905766Speter /* 906766Speter * Default is read from 907766Speter * standard input. 908766Speter */ 9093833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9103833Speter P2PTR|P2STRTY ); 9113833Speter putLV( "_input" , 0 , 0 , NGLOBAL , 9123833Speter P2PTR|P2STRTY ); 913766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 914766Speter putdot( filename , line ); 915766Speter input->nl_flags |= NUSED; 916766Speter } 917766Speter } else { 9183833Speter putRV( 0, cbn , CURFILEOFFSET , NLOCAL , 9193833Speter P2PTR|P2STRTY ); 9203833Speter putLV( "_input" , 0 , 0 , NGLOBAL , P2PTR|P2STRTY ); 921766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 922766Speter putdot( filename , line ); 923766Speter input->nl_flags |= NUSED; 924766Speter } 925766Speter /* 926766Speter * Loop and process each 927766Speter * of the arguments. 928766Speter */ 929766Speter for (; argv != NIL; argv = argv[2]) { 930766Speter /* 931766Speter * Get the address of the target 932766Speter * on the stack. 933766Speter */ 934766Speter al = argv[1]; 935766Speter if (al == NIL) 936766Speter continue; 937766Speter if (al[0] != T_VAR) { 938766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 939766Speter continue; 940766Speter } 941766Speter codeoff(); 942766Speter ap = stklval(al, MOD|ASGN|NOUSE); 943766Speter codeon(); 944766Speter if (ap == NIL) 945766Speter continue; 946766Speter if (filetype != nl+T1CHAR) { 947766Speter /* 948766Speter * Generalized read, i.e. 949766Speter * from a non-textfile. 950766Speter */ 951766Speter if (incompat(filetype, ap, argv[1] )) { 952766Speter error("Type mismatch in read from non-text file"); 953766Speter continue; 954766Speter } 955766Speter /* 956766Speter * var := file ^; 957766Speter */ 958766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 959766Speter if ( isa( ap , "bsci" ) ) { 960766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 961766Speter } 962766Speter putleaf( P2ICON , 0 , 0 963766Speter , ADDTYPE( 964766Speter ADDTYPE( 965766Speter ADDTYPE( 966766Speter p2type( filetype ) , P2PTR ) 967766Speter , P2FTN ) 968766Speter , P2PTR ) 969766Speter , "_FNIL" ); 970766Speter if (file != NIL) 971766Speter stklval(file, NOFLAGS); 972766Speter else /* Magic */ 9733833Speter putRV( "_input" , 0 , 0 , NGLOBAL , 9743833Speter P2PTR | P2STRTY ); 975766Speter putop( P2CALL , P2INT ); 976766Speter switch ( classify( filetype ) ) { 977766Speter case TBOOL: 978766Speter case TCHAR: 979766Speter case TINT: 980766Speter case TSCAL: 981766Speter case TDOUBLE: 982766Speter case TPTR: 983766Speter putop( P2UNARY P2MUL 984766Speter , p2type( filetype ) ); 985766Speter } 986766Speter switch ( classify( filetype ) ) { 987766Speter case TBOOL: 988766Speter case TCHAR: 989766Speter case TINT: 990766Speter case TSCAL: 991766Speter postcheck( ap ); 992766Speter /* and fall through */ 993766Speter case TDOUBLE: 994766Speter case TPTR: 995766Speter putop( P2ASSIGN , p2type( ap ) ); 996766Speter putdot( filename , line ); 997766Speter break; 998766Speter default: 999766Speter putstrop( P2STASG 1000766Speter , p2type( ap ) 1001766Speter , lwidth( ap ) 1002766Speter , align( ap ) ); 1003766Speter putdot( filename , line ); 1004766Speter break; 1005766Speter } 1006766Speter /* 1007766Speter * get(file); 1008766Speter */ 1009766Speter putleaf( P2ICON , 0 , 0 1010766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1011766Speter , "_GET" ); 10123833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10133833Speter P2PTR|P2STRTY ); 1014766Speter putop( P2CALL , P2INT ); 1015766Speter putdot( filename , line ); 1016766Speter continue; 1017766Speter } 1018766Speter /* 1019766Speter * if you get to here, you are reading from 1020766Speter * a text file. only possiblities are: 1021766Speter * character, integer, real, or scalar. 1022766Speter * read( f , foo , ... ) is done as 1023766Speter * foo := read( f ) with rangechecking 1024766Speter * if appropriate. 1025766Speter */ 1026766Speter typ = classify(ap); 1027766Speter op = rdops(typ); 1028766Speter if (op == NIL) { 1029766Speter error("Can't read %ss from a text file", clnames[typ]); 1030766Speter continue; 1031766Speter } 1032766Speter /* 1033766Speter * left hand side of foo := read( f ) 1034766Speter */ 1035766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 1036766Speter if ( isa( ap , "bsci" ) ) { 1037766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1038766Speter } 1039766Speter switch ( op ) { 1040766Speter case O_READC: 1041766Speter readname = "_READC"; 1042766Speter readtype = P2INT; 1043766Speter break; 1044766Speter case O_READ4: 1045766Speter readname = "_READ4"; 1046766Speter readtype = P2INT; 1047766Speter break; 1048766Speter case O_READ8: 1049766Speter readname = "_READ8"; 1050766Speter readtype = P2DOUBLE; 1051766Speter break; 1052766Speter case O_READE: 1053766Speter readname = "_READE"; 1054766Speter readtype = P2INT; 1055766Speter break; 1056766Speter } 1057766Speter putleaf( P2ICON , 0 , 0 1058766Speter , ADDTYPE( P2FTN | readtype , P2PTR ) 1059766Speter , readname ); 10603833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10613833Speter P2PTR|P2STRTY ); 1062766Speter if ( op == O_READE ) { 1063766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1064766Speter , listnames( ap ) ); 1065766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 1066766Speter , format ); 1067766Speter putop( P2LISTOP , P2INT ); 10681629Speter warning(); 1069766Speter if (opt('s')) { 1070766Speter standard(); 1071766Speter } 10721629Speter error("Reading scalars from text files is non-standard"); 1073766Speter } 1074766Speter putop( P2CALL , readtype ); 1075766Speter if ( isa( ap , "bcsi" ) ) { 1076766Speter postcheck( ap ); 1077766Speter } 1078766Speter putop( P2ASSIGN , p2type( ap ) ); 1079766Speter putdot( filename , line ); 1080766Speter } 1081766Speter /* 1082766Speter * Done with arguments. 1083766Speter * Handle readln and 1084766Speter * insufficient number of args. 1085766Speter */ 1086766Speter if (p->value[0] == O_READLN) { 1087766Speter if (filetype != nl+T1CHAR) 1088766Speter error("Can't 'readln' a non text file"); 1089766Speter putleaf( P2ICON , 0 , 0 1090766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1091766Speter , "_READLN" ); 10923833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , 10933833Speter P2PTR|P2STRTY ); 1094766Speter putop( P2CALL , P2INT ); 1095766Speter putdot( filename , line ); 1096766Speter } else if (argc == 0) 1097766Speter error("read requires an argument"); 1098766Speter return; 1099766Speter 1100766Speter case O_GET: 1101766Speter case O_PUT: 1102766Speter if (argc != 1) { 1103766Speter error("%s expects one argument", p->symbol); 1104766Speter return; 1105766Speter } 11063833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1107766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1108766Speter , "_UNIT" ); 1109766Speter ap = stklval(argv[1], NOFLAGS); 1110766Speter if (ap == NIL) 1111766Speter return; 1112766Speter if (ap->class != FILET) { 1113766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1114766Speter return; 1115766Speter } 1116766Speter putop( P2CALL , P2INT ); 1117766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1118766Speter putdot( filename , line ); 1119766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1120766Speter , op == O_GET ? "_GET" : "_PUT" ); 11213833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1122766Speter putop( P2CALL , P2INT ); 1123766Speter putdot( filename , line ); 1124766Speter return; 1125766Speter 1126766Speter case O_RESET: 1127766Speter case O_REWRITE: 1128766Speter if (argc == 0 || argc > 2) { 1129766Speter error("%s expects one or two arguments", p->symbol); 1130766Speter return; 1131766Speter } 1132766Speter if (opt('s') && argc == 2) { 1133766Speter standard(); 1134766Speter error("Two argument forms of reset and rewrite are non-standard"); 1135766Speter } 1136766Speter putleaf( P2ICON , 0 , 0 , P2INT 1137766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 1138766Speter ap = stklval(argv[1], MOD|NOUSE); 1139766Speter if (ap == NIL) 1140766Speter return; 1141766Speter if (ap->class != FILET) { 1142766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1143766Speter return; 1144766Speter } 1145766Speter if (argc == 2) { 1146766Speter /* 1147766Speter * Optional second argument 1148766Speter * is a string name of a 1149766Speter * UNIX (R) file to be associated. 1150766Speter */ 1151766Speter al = argv[2]; 1152766Speter al = stkrval(al[1], NOFLAGS , RREQ ); 1153766Speter if (al == NIL) 1154766Speter return; 1155766Speter if (classify(al) != TSTR) { 1156766Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 1157766Speter return; 1158766Speter } 1159766Speter strnglen = width(al); 1160766Speter } else { 1161766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 1162766Speter strnglen = 0; 1163766Speter } 1164766Speter putop( P2LISTOP , P2INT ); 1165766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 1166766Speter putop( P2LISTOP , P2INT ); 1167766Speter putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 ); 1168766Speter putop( P2LISTOP , P2INT ); 1169766Speter putop( P2CALL , P2INT ); 1170766Speter putdot( filename , line ); 1171766Speter return; 1172766Speter 1173766Speter case O_NEW: 1174766Speter case O_DISPOSE: 1175766Speter if (argc == 0) { 1176766Speter error("%s expects at least one argument", p->symbol); 1177766Speter return; 1178766Speter } 1179766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1180766Speter , op == O_DISPOSE ? "_DISPOSE" : 1181766Speter opt('t') ? "_NEWZ" : "_NEW" ); 1182766Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1183766Speter if (ap == NIL) 1184766Speter return; 1185766Speter if (ap->class != PTR) { 1186766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1187766Speter return; 1188766Speter } 1189766Speter ap = ap->type; 1190766Speter if (ap == NIL) 1191766Speter return; 1192766Speter argv = argv[2]; 1193766Speter if (argv != NIL) { 1194766Speter if (ap->class != RECORD) { 1195766Speter error("Record required when specifying variant tags"); 1196766Speter return; 1197766Speter } 1198766Speter for (; argv != NIL; argv = argv[2]) { 1199766Speter if (ap->ptr[NL_VARNT] == NIL) { 1200766Speter error("Too many tag fields"); 1201766Speter return; 1202766Speter } 1203766Speter if (!isconst(argv[1])) { 1204766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1205766Speter return; 1206766Speter } 1207766Speter gconst(argv[1]); 1208766Speter if (con.ctype == NIL) 1209766Speter return; 1210766Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 1211766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1212766Speter return; 1213766Speter } 1214766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1215766Speter if (ap->range[0] == con.crval) 1216766Speter break; 1217766Speter if (ap == NIL) { 1218766Speter error("No variant case label value equals specified constant value"); 1219766Speter return; 1220766Speter } 1221766Speter ap = ap->ptr[NL_VTOREC]; 1222766Speter } 1223766Speter } 1224766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1225766Speter putop( P2LISTOP , P2INT ); 1226766Speter putop( P2CALL , P2INT ); 1227766Speter putdot( filename , line ); 1228766Speter return; 1229766Speter 1230766Speter case O_DATE: 1231766Speter case O_TIME: 1232766Speter if (argc != 1) { 1233766Speter error("%s expects one argument", p->symbol); 1234766Speter return; 1235766Speter } 1236766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1237766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 1238766Speter ap = stklval(argv[1], MOD|NOUSE); 1239766Speter if (ap == NIL) 1240766Speter return; 1241766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1242766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1243766Speter return; 1244766Speter } 1245766Speter putop( P2CALL , P2INT ); 1246766Speter putdot( filename , line ); 1247766Speter return; 1248766Speter 1249766Speter case O_HALT: 1250766Speter if (argc != 0) { 1251766Speter error("halt takes no arguments"); 1252766Speter return; 1253766Speter } 1254766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1255766Speter , "_HALT" ); 1256766Speter 1257766Speter putop( P2UNARY P2CALL , P2INT ); 1258766Speter putdot( filename , line ); 1259766Speter noreach = 1; 1260766Speter return; 1261766Speter 1262766Speter case O_ARGV: 1263766Speter if (argc != 2) { 1264766Speter error("argv takes two arguments"); 1265766Speter return; 1266766Speter } 1267766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1268766Speter , "_ARGV" ); 1269766Speter ap = stkrval(argv[1], NIL , RREQ ); 1270766Speter if (ap == NIL) 1271766Speter return; 1272766Speter if (isnta(ap, "i")) { 1273766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1274766Speter return; 1275766Speter } 1276766Speter al = argv[2]; 1277766Speter ap = stklval(al[1], MOD|NOUSE); 1278766Speter if (ap == NIL) 1279766Speter return; 1280766Speter if (classify(ap) != TSTR) { 1281766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1282766Speter return; 1283766Speter } 1284766Speter putop( P2LISTOP , P2INT ); 1285766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1286766Speter putop( P2LISTOP , P2INT ); 1287766Speter putop( P2CALL , P2INT ); 1288766Speter putdot( filename , line ); 1289766Speter return; 1290766Speter 1291766Speter case O_STLIM: 1292766Speter if (argc != 1) { 1293766Speter error("stlimit requires one argument"); 1294766Speter return; 1295766Speter } 1296766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1297766Speter , "_STLIM" ); 1298766Speter ap = stkrval(argv[1], NIL , RREQ ); 1299766Speter if (ap == NIL) 1300766Speter return; 1301766Speter if (isnta(ap, "i")) { 1302766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1303766Speter return; 1304766Speter } 1305766Speter putop( P2CALL , P2INT ); 1306766Speter putdot( filename , line ); 1307766Speter return; 1308766Speter 1309766Speter case O_REMOVE: 1310766Speter if (argc != 1) { 1311766Speter error("remove expects one argument"); 1312766Speter return; 1313766Speter } 1314766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1315766Speter , "_REMOVE" ); 1316766Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 1317766Speter if (ap == NIL) 1318766Speter return; 1319766Speter if (classify(ap) != TSTR) { 1320766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1321766Speter return; 1322766Speter } 1323766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1324766Speter putop( P2LISTOP , P2INT ); 1325766Speter putop( P2CALL , P2INT ); 1326766Speter putdot( filename , line ); 1327766Speter return; 1328766Speter 1329766Speter case O_LLIMIT: 1330766Speter if (argc != 2) { 1331766Speter error("linelimit expects two arguments"); 1332766Speter return; 1333766Speter } 1334766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1335766Speter , "_LLIMIT" ); 1336766Speter ap = stklval(argv[1], NOFLAGS|NOUSE); 1337766Speter if (ap == NIL) 1338766Speter return; 1339766Speter if (!text(ap)) { 1340766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1341766Speter return; 1342766Speter } 1343766Speter al = argv[2]; 1344766Speter ap = stkrval(al[1], NIL , RREQ ); 1345766Speter if (ap == NIL) 1346766Speter return; 1347766Speter if (isnta(ap, "i")) { 1348766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1349766Speter return; 1350766Speter } 1351766Speter putop( P2LISTOP , P2INT ); 1352766Speter putop( P2CALL , P2INT ); 1353766Speter putdot( filename , line ); 1354766Speter return; 1355766Speter case O_PAGE: 1356766Speter if (argc != 1) { 1357766Speter error("page expects one argument"); 1358766Speter return; 1359766Speter } 13603833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1361766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1362766Speter , "_UNIT" ); 1363766Speter ap = stklval(argv[1], NOFLAGS); 1364766Speter if (ap == NIL) 1365766Speter return; 1366766Speter if (!text(ap)) { 1367766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1368766Speter return; 1369766Speter } 1370766Speter putop( P2CALL , P2INT ); 1371766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1372766Speter putdot( filename , line ); 1373766Speter if ( opt( 't' ) ) { 1374766Speter putleaf( P2ICON , 0 , 0 1375766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1376766Speter , "_PAGE" ); 13773833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1378766Speter } else { 1379766Speter putleaf( P2ICON , 0 , 0 1380766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1381766Speter , "_fputc" ); 1382766Speter putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 ); 1383766Speter putleaf( P2ICON , 0 , 0 1384766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1385766Speter , "_ACTFILE" ); 13863833Speter putRV( 0 , cbn , CURFILEOFFSET , NLOCAL , P2PTR|P2STRTY ); 1387766Speter putop( P2CALL , P2INT ); 1388766Speter putop( P2LISTOP , P2INT ); 1389766Speter } 1390766Speter putop( P2CALL , P2INT ); 1391766Speter putdot( filename , line ); 1392766Speter return; 1393766Speter 1394766Speter case O_PACK: 1395766Speter if (argc != 3) { 1396766Speter error("pack expects three arguments"); 1397766Speter return; 1398766Speter } 1399766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1400766Speter , "_PACK" ); 1401766Speter pu = "pack(a,i,z)"; 1402766Speter pua = (al = argv)[1]; 1403766Speter pui = (al = al[2])[1]; 1404766Speter puz = (al = al[2])[1]; 1405766Speter goto packunp; 1406766Speter case O_UNPACK: 1407766Speter if (argc != 3) { 1408766Speter error("unpack expects three arguments"); 1409766Speter return; 1410766Speter } 1411766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1412766Speter , "_UNPACK" ); 1413766Speter pu = "unpack(z,a,i)"; 1414766Speter puz = (al = argv)[1]; 1415766Speter pua = (al = al[2])[1]; 1416766Speter pui = (al = al[2])[1]; 1417766Speter packunp: 1418766Speter ap = stkrval((int *) pui, NLNIL , RREQ ); 1419766Speter if (ap == NIL) 1420766Speter return; 1421766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1422766Speter if (ap == NIL) 1423766Speter return; 1424766Speter if (ap->class != ARRAY) { 1425766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1426766Speter return; 1427766Speter } 1428766Speter putop( P2LISTOP , P2INT ); 1429766Speter al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1430766Speter if (al->class != ARRAY) { 1431766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1432766Speter return; 1433766Speter } 1434766Speter if (al->type == NIL || ap->type == NIL) 1435766Speter return; 1436766Speter if (al->type != ap->type) { 1437766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1438766Speter return; 1439766Speter } 1440766Speter putop( P2LISTOP , P2INT ); 1441766Speter k = width(al); 1442766Speter itemwidth = width(ap->type); 1443766Speter ap = ap->chain; 1444766Speter al = al->chain; 1445766Speter if (ap->chain != NIL || al->chain != NIL) { 1446766Speter error("%s requires a and z to be single dimension arrays", pu); 1447766Speter return; 1448766Speter } 1449766Speter if (ap == NIL || al == NIL) 1450766Speter return; 1451766Speter /* 1452766Speter * al is the range for z i.e. u..v 1453766Speter * ap is the range for a i.e. m..n 1454766Speter * i will be n-m+1 1455766Speter * j will be v-u+1 1456766Speter */ 1457766Speter i = ap->range[1] - ap->range[0] + 1; 1458766Speter j = al->range[1] - al->range[0] + 1; 1459766Speter if (i < j) { 1460766Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1461766Speter return; 1462766Speter } 1463766Speter /* 1464766Speter * get n-m-(v-u) and m for the interpreter 1465766Speter */ 1466766Speter i -= j; 1467766Speter j = ap->range[0]; 1468766Speter putleaf( P2ICON , itemwidth , 0 , P2INT , 0 ); 1469766Speter putop( P2LISTOP , P2INT ); 1470766Speter putleaf( P2ICON , j , 0 , P2INT , 0 ); 1471766Speter putop( P2LISTOP , P2INT ); 1472766Speter putleaf( P2ICON , i , 0 , P2INT , 0 ); 1473766Speter putop( P2LISTOP , P2INT ); 1474766Speter putleaf( P2ICON , k , 0 , P2INT , 0 ); 1475766Speter putop( P2LISTOP , P2INT ); 1476766Speter putop( P2CALL , P2INT ); 1477766Speter putdot( filename , line ); 1478766Speter return; 1479766Speter case 0: 1480766Speter error("%s is an unimplemented 6400 extension", p->symbol); 1481766Speter return; 1482766Speter 1483766Speter default: 1484766Speter panic("proc case"); 1485766Speter } 1486766Speter } 1487766Speter #endif PC 1488