1766Speter /* Copyright (c) 1979 Regents of the University of California */ 2766Speter 3*3180Smckusic static char sccsid[] = "@(#)pcproc.c 1.4 03/10/81"; 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; 55766Speter char *readname; 56766Speter long tempoff; 57766Speter long readtype; 58766Speter 59766Speter #define CONPREC 4 60766Speter #define VARPREC 8 61766Speter #define CONWIDTH 1 62766Speter #define VARWIDTH 2 63766Speter #define SKIP 16 64766Speter 65766Speter /* 66766Speter * Verify that the name is 67766Speter * defined and is that of a 68766Speter * procedure. 69766Speter */ 70766Speter p = lookup(r[2]); 71766Speter if (p == NIL) { 72766Speter rvlist(r[3]); 73766Speter return; 74766Speter } 751197Speter if (p->class != PROC && p->class != FPROC) { 76766Speter error("Can't call %s, its %s not a procedure", p->symbol, classes[p->class]); 77766Speter rvlist(r[3]); 78766Speter return; 79766Speter } 80766Speter argv = r[3]; 81766Speter 82766Speter /* 83766Speter * Call handles user defined 84766Speter * procedures and functions. 85766Speter */ 86766Speter if (bn != 0) { 87766Speter call(p, argv, PROC, bn); 88766Speter return; 89766Speter } 90766Speter 91766Speter /* 92766Speter * Call to built-in procedure. 93766Speter * Count the arguments. 94766Speter */ 95766Speter argc = 0; 96766Speter for (al = argv; al != NIL; al = al[2]) 97766Speter argc++; 98766Speter 99766Speter /* 100766Speter * Switch on the operator 101766Speter * associated with the built-in 102766Speter * procedure in the namelist 103766Speter */ 104766Speter op = p->value[0] &~ NSTAND; 105766Speter if (opt('s') && (p->value[0] & NSTAND)) { 106766Speter standard(); 107766Speter error("%s is a nonstandard procedure", p->symbol); 108766Speter } 109766Speter switch (op) { 110766Speter 111766Speter case O_ABORT: 112766Speter if (argc != 0) 113766Speter error("null takes no arguments"); 114766Speter return; 115766Speter 116766Speter case O_FLUSH: 117766Speter if (argc == 0) { 118766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 119766Speter putop( P2UNARY P2CALL , P2INT ); 120766Speter putdot( filename , line ); 121766Speter return; 122766Speter } 123766Speter if (argc != 1) { 124766Speter error("flush takes at most one argument"); 125766Speter return; 126766Speter } 127766Speter putleaf( P2ICON , 0 , 0 128766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 129766Speter , "_FLUSH" ); 130766Speter ap = stklval(argv[1], NOFLAGS); 131766Speter if (ap == NIL) 132766Speter return; 133766Speter if (ap->class != FILET) { 134766Speter error("flush's argument must be a file, not %s", nameof(ap)); 135766Speter return; 136766Speter } 137766Speter putop( P2CALL , P2INT ); 138766Speter putdot( filename , line ); 139766Speter return; 140766Speter 141766Speter case O_MESSAGE: 142766Speter case O_WRITEF: 143766Speter case O_WRITLN: 144766Speter /* 145766Speter * Set up default file "output"'s type 146766Speter */ 147766Speter file = NIL; 148766Speter filetype = nl+T1CHAR; 149766Speter /* 150766Speter * Determine the file implied 151766Speter * for the write and generate 152766Speter * code to make it the active file. 153766Speter */ 154766Speter if (op == O_MESSAGE) { 155766Speter /* 156766Speter * For message, all that matters 157766Speter * is that the filetype is 158766Speter * a character file. 159766Speter * Thus "output" will suit us fine. 160766Speter */ 161766Speter putleaf( P2ICON , 0 , 0 , P2INT , "_PFLUSH" ); 162766Speter putop( P2UNARY P2CALL , P2INT ); 163766Speter putdot( filename , line ); 164766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 165766Speter putLV( "__err" , 0 , 0 , P2PTR|P2STRTY ); 166766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 167766Speter putdot( filename , line ); 168766Speter } else if (argv != NIL && (al = argv[1])[0] != T_WEXP) { 169766Speter /* 170766Speter * If there is a first argument which has 171766Speter * no write widths, then it is potentially 172766Speter * a file name. 173766Speter */ 174766Speter codeoff(); 175766Speter ap = stkrval(argv[1], NIL , RREQ ); 176766Speter codeon(); 177766Speter if (ap == NIL) 178766Speter argv = argv[2]; 179766Speter if (ap != NIL && ap->class == FILET) { 180766Speter /* 181766Speter * Got "write(f, ...", make 182766Speter * f the active file, and save 183766Speter * it and its type for use in 184766Speter * processing the rest of the 185766Speter * arguments to write. 186766Speter */ 187766Speter putRV( 0 , cbn , CURFILEOFFSET 188766Speter , P2PTR|P2STRTY ); 189766Speter putleaf( P2ICON , 0 , 0 190766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 191766Speter , "_UNIT" ); 192766Speter file = argv[1]; 193766Speter filetype = ap->type; 194766Speter stklval(argv[1], NOFLAGS); 195766Speter putop( P2CALL , P2INT ); 196766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 197766Speter putdot( filename , line ); 198766Speter /* 199766Speter * Skip over the first argument 200766Speter */ 201766Speter argv = argv[2]; 202766Speter argc--; 203766Speter } else { 204766Speter /* 205766Speter * Set up for writing on 206766Speter * standard output. 207766Speter */ 208766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 209766Speter putLV( "_output" , 0 , 0 , P2PTR|P2STRTY ); 210766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 211766Speter putdot( filename , line ); 212766Speter } 213766Speter } else { 214766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 215766Speter putLV( "_output" , 0 , 0 , P2PTR|P2STRTY ); 216766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 217766Speter putdot( filename , line ); 218766Speter } 219766Speter /* 220766Speter * Loop and process each 221766Speter * of the arguments. 222766Speter */ 223766Speter for (; argv != NIL; argv = argv[2]) { 224766Speter /* 225766Speter * fmtspec indicates the type (CONstant or VARiable) 226766Speter * and number (none, WIDTH, and/or PRECision) 227766Speter * of the fields in the printf format for this 228766Speter * output variable. 229766Speter * stkcnt is the number of longs pushed on the stack 230766Speter * fmt is the format output indicator (D, E, F, O, X, S) 231766Speter * fmtstart = 0 for leading blank; = 1 for no blank 232766Speter */ 233766Speter fmtspec = NIL; 234766Speter stkcnt = 0; 235766Speter fmt = 'D'; 236766Speter fmtstart = 1; 237766Speter al = argv[1]; 238766Speter if (al == NIL) 239766Speter continue; 240766Speter if (al[0] == T_WEXP) 241766Speter alv = al[1]; 242766Speter else 243766Speter alv = al; 244766Speter if (alv == NIL) 245766Speter continue; 246766Speter codeoff(); 247766Speter ap = stkrval(alv, NIL , RREQ ); 248766Speter codeon(); 249766Speter if (ap == NIL) 250766Speter continue; 251766Speter typ = classify(ap); 252766Speter if (al[0] == T_WEXP) { 253766Speter /* 254766Speter * Handle width expressions. 255766Speter * The basic game here is that width 256766Speter * expressions get evaluated. If they 257766Speter * are constant, the value is placed 258766Speter * directly in the format string. 259766Speter * Otherwise the value is pushed onto 260766Speter * the stack and an indirection is 261766Speter * put into the format string. 262766Speter */ 263766Speter if (al[3] == OCT) 264766Speter fmt = 'O'; 265766Speter else if (al[3] == HEX) 266766Speter fmt = 'X'; 267766Speter else if (al[3] != NIL) { 268766Speter /* 269766Speter * Evaluate second format spec 270766Speter */ 271766Speter if ( constval(al[3]) 272766Speter && isa( con.ctype , "i" ) ) { 273766Speter fmtspec += CONPREC; 274766Speter prec = con.crval; 275766Speter } else { 276766Speter fmtspec += VARPREC; 277766Speter } 278766Speter fmt = 'f'; 279766Speter switch ( typ ) { 280766Speter case TINT: 281766Speter if ( opt( 's' ) ) { 282766Speter standard(); 283766Speter error("Writing %ss with two write widths is non-standard", clnames[typ]); 284766Speter } 285766Speter /* and fall through */ 286766Speter case TDOUBLE: 287766Speter break; 288766Speter default: 289766Speter error("Cannot write %ss with two write widths", clnames[typ]); 290766Speter continue; 291766Speter } 292766Speter } 293766Speter /* 294766Speter * Evaluate first format spec 295766Speter */ 296766Speter if (al[2] != NIL) { 297766Speter if ( constval(al[2]) 298766Speter && isa( con.ctype , "i" ) ) { 299766Speter fmtspec += CONWIDTH; 300766Speter field = con.crval; 301766Speter } else { 302766Speter fmtspec += VARWIDTH; 303766Speter } 304766Speter } 305766Speter if ((fmtspec & CONPREC) && prec < 0 || 306766Speter (fmtspec & CONWIDTH) && field < 0) { 307766Speter error("Negative widths are not allowed"); 308766Speter continue; 309766Speter } 310*3180Smckusic if ( opt('s') && 311*3180Smckusic ((fmtspec & CONPREC) && prec == 0 || 312*3180Smckusic (fmtspec & CONWIDTH) && field == 0)) { 313*3180Smckusic standard(); 314*3180Smckusic error("Zero widths are non-standard"); 315*3180Smckusic } 316766Speter } 317766Speter if (filetype != nl+T1CHAR) { 318766Speter if (fmt == 'O' || fmt == 'X') { 319766Speter error("Oct/hex allowed only on text files"); 320766Speter continue; 321766Speter } 322766Speter if (fmtspec) { 323766Speter error("Write widths allowed only on text files"); 324766Speter continue; 325766Speter } 326766Speter /* 327766Speter * Generalized write, i.e. 328766Speter * to a non-textfile. 329766Speter */ 330766Speter putleaf( P2ICON , 0 , 0 331766Speter , ADDTYPE( 332766Speter ADDTYPE( 333766Speter ADDTYPE( p2type( filetype ) 334766Speter , P2PTR ) 335766Speter , P2FTN ) 336766Speter , P2PTR ) 337766Speter , "_FNIL" ); 338766Speter stklval(file, NOFLAGS); 339766Speter putop( P2CALL 340766Speter , ADDTYPE( p2type( filetype ) , P2PTR ) ); 341766Speter putop( P2UNARY P2MUL , p2type( filetype ) ); 342766Speter /* 343766Speter * file^ := ... 344766Speter */ 345766Speter switch ( classify( filetype ) ) { 346766Speter case TBOOL: 347766Speter case TCHAR: 348766Speter case TINT: 349766Speter case TSCAL: 350766Speter precheck( filetype , "_RANG4" , "_RSGN4" ); 351766Speter /* and fall through */ 352766Speter case TDOUBLE: 353766Speter case TPTR: 354766Speter ap = rvalue( argv[1] , filetype , RREQ ); 355766Speter break; 356766Speter default: 357766Speter ap = rvalue( argv[1] , filetype , LREQ ); 358766Speter break; 359766Speter } 360766Speter if (ap == NIL) 361766Speter continue; 362766Speter if (incompat(ap, filetype, argv[1])) { 363766Speter cerror("Type mismatch in write to non-text file"); 364766Speter continue; 365766Speter } 366766Speter switch ( classify( filetype ) ) { 367766Speter case TBOOL: 368766Speter case TCHAR: 369766Speter case TINT: 370766Speter case TSCAL: 371766Speter postcheck( filetype ); 372766Speter /* and fall through */ 373766Speter case TDOUBLE: 374766Speter case TPTR: 375766Speter putop( P2ASSIGN , p2type( filetype ) ); 376766Speter putdot( filename , line ); 377766Speter break; 378766Speter default: 379766Speter putstrop( P2STASG 380766Speter , p2type( filetype ) 381766Speter , lwidth( filetype ) 382766Speter , align( filetype ) ); 383766Speter putdot( filename , line ); 384766Speter break; 385766Speter } 386766Speter /* 387766Speter * put(file) 388766Speter */ 389766Speter putleaf( P2ICON , 0 , 0 390766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 391766Speter , "_PUT" ); 392766Speter putRV( 0 , cbn , CURFILEOFFSET 393766Speter , P2PTR|P2STRTY ); 394766Speter putop( P2CALL , P2INT ); 395766Speter putdot( filename , line ); 396766Speter continue; 397766Speter } 398766Speter /* 399766Speter * Write to a textfile 400766Speter * 401766Speter * Evaluate the expression 402766Speter * to be written. 403766Speter */ 404766Speter if (fmt == 'O' || fmt == 'X') { 405766Speter if (opt('s')) { 406766Speter standard(); 407766Speter error("Oct and hex are non-standard"); 408766Speter } 409766Speter if (typ == TSTR || typ == TDOUBLE) { 410766Speter error("Can't write %ss with oct/hex", clnames[typ]); 411766Speter continue; 412766Speter } 413766Speter if (typ == TCHAR || typ == TBOOL) 414766Speter typ = TINT; 415766Speter } 416766Speter /* 417766Speter * If there is no format specified by the programmer, 418766Speter * implement the default. 419766Speter */ 420766Speter switch (typ) { 421766Speter case TINT: 422766Speter if (fmt == 'f') { 423766Speter typ = TDOUBLE; 424766Speter goto tdouble; 425766Speter } 426766Speter if (fmtspec == NIL) { 427766Speter if (fmt == 'D') 428766Speter field = 10; 429766Speter else if (fmt == 'X') 430766Speter field = 8; 431766Speter else if (fmt == 'O') 432766Speter field = 11; 433766Speter else 434766Speter panic("fmt1"); 435766Speter fmtspec = CONWIDTH; 436766Speter } 437766Speter break; 438766Speter case TCHAR: 439766Speter tchar: 440766Speter fmt = 'c'; 441766Speter break; 442766Speter case TSCAL: 4431629Speter warning(); 444766Speter if (opt('s')) { 445766Speter standard(); 446766Speter } 4471629Speter error("Writing scalars to text files is non-standard"); 448766Speter case TBOOL: 449766Speter fmt = 's'; 450766Speter break; 451766Speter case TDOUBLE: 452766Speter tdouble: 453766Speter switch (fmtspec) { 454766Speter case NIL: 455766Speter field = 21; 456766Speter prec = 14; 457766Speter fmt = 'E'; 458766Speter fmtspec = CONWIDTH + CONPREC; 459766Speter break; 460766Speter case CONWIDTH: 461766Speter if (--field < 1) 462766Speter field = 1; 463766Speter prec = field - 7; 464766Speter if (prec < 1) 465766Speter prec = 1; 466766Speter fmtspec += CONPREC; 467766Speter fmt = 'E'; 468766Speter break; 469766Speter case VARWIDTH: 470766Speter fmtspec += VARPREC; 471766Speter fmt = 'E'; 472766Speter break; 473766Speter case CONWIDTH + CONPREC: 474766Speter case CONWIDTH + VARPREC: 475766Speter if (--field < 1) 476766Speter field = 1; 477766Speter } 478766Speter format[0] = ' '; 479766Speter fmtstart = 0; 480766Speter break; 481766Speter case TSTR: 482766Speter constval( alv ); 483766Speter switch ( classify( con.ctype ) ) { 484766Speter case TCHAR: 485766Speter typ = TCHAR; 486766Speter goto tchar; 487766Speter case TSTR: 488766Speter strptr = con.cpval; 489766Speter for (strnglen = 0; *strptr++; strnglen++) /* void */; 490766Speter strptr = con.cpval; 491766Speter break; 492766Speter default: 493766Speter strnglen = width(ap); 494766Speter break; 495766Speter } 496766Speter fmt = 's'; 497766Speter strfmt = fmtspec; 498766Speter if (fmtspec == NIL) { 499766Speter fmtspec = SKIP; 500766Speter break; 501766Speter } 502766Speter if (fmtspec & CONWIDTH) { 503766Speter if (field <= strnglen) 504766Speter fmtspec = SKIP; 505766Speter else 506766Speter field -= strnglen; 507766Speter } 508766Speter break; 509766Speter default: 510766Speter error("Can't write %ss to a text file", clnames[typ]); 511766Speter continue; 512766Speter } 513766Speter /* 514766Speter * Generate the format string 515766Speter */ 516766Speter switch (fmtspec) { 517766Speter default: 518766Speter panic("fmt2"); 519766Speter case NIL: 520766Speter if (fmt == 'c') { 521766Speter if ( opt( 't' ) ) { 522766Speter putleaf( P2ICON , 0 , 0 523766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 524766Speter , "_WRITEC" ); 525766Speter putRV( 0 , cbn , CURFILEOFFSET 526766Speter , P2PTR|P2STRTY ); 527766Speter stkrval( alv , NIL , RREQ ); 528766Speter putop( P2LISTOP , P2INT ); 529766Speter } else { 530766Speter putleaf( P2ICON , 0 , 0 531766Speter , ADDTYPE( P2FTN|P2INT , P2PTR ) 532766Speter , "_fputc" ); 533766Speter stkrval( alv , NIL , RREQ ); 534766Speter } 535766Speter putleaf( P2ICON , 0 , 0 536766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 537766Speter , "_ACTFILE" ); 538766Speter putRV( 0, cbn , CURFILEOFFSET 539766Speter , P2PTR|P2STRTY ); 540766Speter putop( P2CALL , P2INT ); 541766Speter putop( P2LISTOP , P2INT ); 542766Speter putop( P2CALL , P2INT ); 543766Speter putdot( filename , line ); 544766Speter } else { 545766Speter sprintf(&format[1], "%%%c", fmt); 546766Speter goto fmtgen; 547766Speter } 548766Speter case SKIP: 549766Speter break; 550766Speter case CONWIDTH: 551766Speter sprintf(&format[1], "%%%1D%c", field, fmt); 552766Speter goto fmtgen; 553766Speter case VARWIDTH: 554766Speter sprintf(&format[1], "%%*%c", fmt); 555766Speter goto fmtgen; 556766Speter case CONWIDTH + CONPREC: 557766Speter sprintf(&format[1], "%%%1D.%1D%c", field, prec, fmt); 558766Speter goto fmtgen; 559766Speter case CONWIDTH + VARPREC: 560766Speter sprintf(&format[1], "%%%1D.*%c", field, fmt); 561766Speter goto fmtgen; 562766Speter case VARWIDTH + CONPREC: 563766Speter sprintf(&format[1], "%%*.%1D%c", prec, fmt); 564766Speter goto fmtgen; 565766Speter case VARWIDTH + VARPREC: 566766Speter sprintf(&format[1], "%%*.*%c", fmt); 567766Speter fmtgen: 568766Speter if ( opt( 't' ) ) { 569766Speter putleaf( P2ICON , 0 , 0 570766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 571766Speter , "_WRITEF" ); 572766Speter putRV( 0 , cbn , CURFILEOFFSET 573766Speter , P2PTR|P2STRTY ); 574766Speter putleaf( P2ICON , 0 , 0 575766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 576766Speter , "_ACTFILE" ); 577766Speter putRV( 0 , cbn , CURFILEOFFSET 578766Speter , P2PTR|P2STRTY ); 579766Speter putop( P2CALL , P2INT ); 580766Speter putop( P2LISTOP , P2INT ); 581766Speter } else { 582766Speter putleaf( P2ICON , 0 , 0 583766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 584766Speter , "_fprintf" ); 585766Speter putleaf( P2ICON , 0 , 0 586766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 587766Speter , "_ACTFILE" ); 588766Speter putRV( 0 , cbn , CURFILEOFFSET 589766Speter , P2PTR|P2STRTY ); 590766Speter putop( P2CALL , P2INT ); 591766Speter } 592766Speter putCONG( &format[ fmtstart ] 593766Speter , strlen( &format[ fmtstart ] ) 594766Speter , LREQ ); 595766Speter putop( P2LISTOP , P2INT ); 596766Speter if ( fmtspec & VARWIDTH ) { 597766Speter /* 598766Speter * either 599766Speter * ,(temp=width,MAX(temp,...)), 600766Speter * or 601766Speter * , MAX( width , ... ) , 602766Speter */ 603766Speter if ( ( typ == TDOUBLE && al[3] == NIL ) 604766Speter || typ == TSTR ) { 605766Speter sizes[ cbn ].om_off -= sizeof( int ); 606766Speter tempoff = sizes[ cbn ].om_off; 607766Speter putlbracket( ftnno , -tempoff ); 608766Speter if ( tempoff < sizes[ cbn ].om_max ) { 609766Speter sizes[ cbn ].om_max = tempoff; 610766Speter } 611766Speter putRV( 0 , cbn , tempoff , P2INT ); 612766Speter ap = stkrval( al[2] , NIL , RREQ ); 613766Speter putop( P2ASSIGN , P2INT ); 614766Speter putleaf( P2ICON , 0 , 0 615766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 616766Speter , "_MAX" ); 617766Speter putRV( 0 , cbn , tempoff , P2INT ); 618766Speter } else { 619766Speter if (opt('t') 620766Speter || typ == TSTR || typ == TDOUBLE) { 621766Speter putleaf( P2ICON , 0 , 0 622766Speter ,ADDTYPE( P2FTN | P2INT, P2PTR ) 623766Speter ,"_MAX" ); 624766Speter } 625766Speter ap = stkrval( al[2] , NIL , RREQ ); 626766Speter } 627766Speter if (ap == NIL) 628766Speter continue; 629766Speter if (isnta(ap,"i")) { 630766Speter error("First write width must be integer, not %s", nameof(ap)); 631766Speter continue; 632766Speter } 633766Speter switch ( typ ) { 634766Speter case TDOUBLE: 635766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 636766Speter putop( P2LISTOP , P2INT ); 637766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 638766Speter putop( P2LISTOP , P2INT ); 639766Speter putop( P2CALL , P2INT ); 640766Speter if ( al[3] == NIL ) { 641766Speter /* 642766Speter * finish up the comma op 643766Speter */ 644766Speter putop( P2COMOP , P2INT ); 645766Speter fmtspec &= ~VARPREC; 646766Speter putop( P2LISTOP , P2INT ); 647766Speter putleaf( P2ICON , 0 , 0 648766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 649766Speter , "_MAX" ); 650766Speter putRV( 0 , cbn , tempoff , P2INT ); 651766Speter sizes[ cbn ].om_off += sizeof( int ); 652766Speter putleaf( P2ICON , 8 , 0 , P2INT , 0 ); 653766Speter putop( P2LISTOP , P2INT ); 654766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 655766Speter putop( P2LISTOP , P2INT ); 656766Speter putop( P2CALL , P2INT ); 657766Speter } 658766Speter putop( P2LISTOP , P2INT ); 659766Speter break; 660766Speter case TSTR: 661766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 662766Speter putop( P2LISTOP , P2INT ); 663766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 664766Speter putop( P2LISTOP , P2INT ); 665766Speter putop( P2CALL , P2INT ); 666766Speter putop( P2COMOP , P2INT ); 667766Speter putop( P2LISTOP , P2INT ); 668766Speter break; 669766Speter default: 670766Speter if (opt('t')) { 671766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 672766Speter putop( P2LISTOP , P2INT ); 673766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 674766Speter putop( P2LISTOP , P2INT ); 675766Speter putop( P2CALL , P2INT ); 676766Speter } 677766Speter putop( P2LISTOP , P2INT ); 678766Speter break; 679766Speter } 680766Speter } 681766Speter /* 682766Speter * If there is a variable precision, 683766Speter * evaluate it 684766Speter */ 685766Speter if (fmtspec & VARPREC) { 686766Speter if (opt('t')) { 687766Speter putleaf( P2ICON , 0 , 0 688766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 689766Speter , "_MAX" ); 690766Speter } 691766Speter ap = stkrval( al[3] , NIL , RREQ ); 692766Speter if (ap == NIL) 693766Speter continue; 694766Speter if (isnta(ap,"i")) { 695766Speter error("Second write width must be integer, not %s", nameof(ap)); 696766Speter continue; 697766Speter } 698766Speter if (opt('t')) { 699766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 700766Speter putop( P2LISTOP , P2INT ); 701766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 702766Speter putop( P2LISTOP , P2INT ); 703766Speter putop( P2CALL , P2INT ); 704766Speter } 705766Speter putop( P2LISTOP , P2INT ); 706766Speter } 707766Speter /* 708766Speter * evaluate the thing we want printed. 709766Speter */ 710766Speter switch ( typ ) { 711766Speter case TCHAR: 712766Speter case TINT: 713766Speter stkrval( alv , NIL , RREQ ); 714766Speter putop( P2LISTOP , P2INT ); 715766Speter break; 716766Speter case TDOUBLE: 717766Speter ap = stkrval( alv , NIL , RREQ ); 718766Speter if ( isnta( ap , "d" ) ) { 719766Speter putop( P2SCONV , P2DOUBLE ); 720766Speter } 721766Speter putop( P2LISTOP , P2INT ); 722766Speter break; 723766Speter case TSCAL: 724766Speter case TBOOL: 725766Speter putleaf( P2ICON , 0 , 0 726766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 727766Speter , "_NAM" ); 728766Speter ap = stkrval( alv , NIL , RREQ ); 729766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 730766Speter , listnames( ap ) ); 731766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 732766Speter , format ); 733766Speter putop( P2LISTOP , P2INT ); 734766Speter putop( P2CALL , P2INT ); 735766Speter putop( P2LISTOP , P2INT ); 736766Speter break; 737766Speter case TSTR: 738766Speter putCONG( "" , 0 , LREQ ); 739766Speter putop( P2LISTOP , P2INT ); 740766Speter break; 741766Speter } 742766Speter putop( P2CALL , P2INT ); 743766Speter putdot( filename , line ); 744766Speter } 745766Speter /* 746766Speter * Write the string after its blank padding 747766Speter */ 748766Speter if (typ == TSTR ) { 749766Speter if ( opt( 't' ) ) { 750766Speter putleaf( P2ICON , 0 , 0 751766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 752766Speter , "_WRITES" ); 753766Speter putRV( 0 , cbn , CURFILEOFFSET 754766Speter , P2PTR|P2STRTY ); 755766Speter ap = stkrval(alv, NIL , RREQ ); 756766Speter putop( P2LISTOP , P2INT ); 757766Speter } else { 758766Speter putleaf( P2ICON , 0 , 0 759766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 760766Speter , "_fwrite" ); 761766Speter ap = stkrval(alv, NIL , RREQ ); 762766Speter } 763766Speter if (strfmt & VARWIDTH) { 764766Speter /* 765766Speter * min, inline expanded as 766766Speter * temp < len ? temp : len 767766Speter */ 768766Speter putRV( 0 , cbn , tempoff , P2INT ); 769766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 770766Speter putop( P2LT , P2INT ); 771766Speter putRV( 0 , cbn , tempoff , P2INT ); 772766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 773766Speter putop( P2COLON , P2INT ); 774766Speter putop( P2QUEST , P2INT ); 775766Speter } else { 776766Speter if ( ( fmtspec & SKIP ) 777766Speter && ( strfmt & CONWIDTH ) ) { 778766Speter strnglen = field; 779766Speter } 780766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 781766Speter } 782766Speter putop( P2LISTOP , P2INT ); 783766Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 784766Speter putop( P2LISTOP , P2INT ); 785766Speter putleaf( P2ICON , 0 , 0 786766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 787766Speter , "_ACTFILE" ); 788766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 789766Speter putop( P2CALL , P2INT ); 790766Speter putop( P2LISTOP , P2INT ); 791766Speter putop( P2CALL , P2INT ); 792766Speter putdot( filename , line ); 793766Speter } 794766Speter } 795766Speter /* 796766Speter * Done with arguments. 797766Speter * Handle writeln and 798766Speter * insufficent number of args. 799766Speter */ 800766Speter switch (p->value[0] &~ NSTAND) { 801766Speter case O_WRITEF: 802766Speter if (argc == 0) 803766Speter error("Write requires an argument"); 804766Speter break; 805766Speter case O_MESSAGE: 806766Speter if (argc == 0) 807766Speter error("Message requires an argument"); 808766Speter case O_WRITLN: 809766Speter if (filetype != nl+T1CHAR) 810766Speter error("Can't 'writeln' a non text file"); 811766Speter if ( opt( 't' ) ) { 812766Speter putleaf( P2ICON , 0 , 0 813766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 814766Speter , "_WRITLN" ); 815766Speter putRV( 0 , cbn , CURFILEOFFSET 816766Speter , P2PTR|P2STRTY ); 817766Speter } else { 818766Speter putleaf( P2ICON , 0 , 0 819766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 820766Speter , "_fputc" ); 821766Speter putleaf( P2ICON , '\n' , 0 , P2CHAR , 0 ); 822766Speter putleaf( P2ICON , 0 , 0 823766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 824766Speter , "_ACTFILE" ); 825766Speter putRV( 0 , cbn , CURFILEOFFSET 826766Speter , P2PTR|P2STRTY ); 827766Speter putop( P2CALL , P2INT ); 828766Speter putop( P2LISTOP , P2INT ); 829766Speter } 830766Speter putop( P2CALL , P2INT ); 831766Speter putdot( filename , line ); 832766Speter break; 833766Speter } 834766Speter return; 835766Speter 836766Speter case O_READ4: 837766Speter case O_READLN: 838766Speter /* 839766Speter * Set up default 840766Speter * file "input". 841766Speter */ 842766Speter file = NIL; 843766Speter filetype = nl+T1CHAR; 844766Speter /* 845766Speter * Determine the file implied 846766Speter * for the read and generate 847766Speter * code to make it the active file. 848766Speter */ 849766Speter if (argv != NIL) { 850766Speter codeoff(); 851766Speter ap = stkrval(argv[1], NIL , RREQ ); 852766Speter codeon(); 853766Speter if (ap == NIL) 854766Speter argv = argv[2]; 855766Speter if (ap != NIL && ap->class == FILET) { 856766Speter /* 857766Speter * Got "read(f, ...", make 858766Speter * f the active file, and save 859766Speter * it and its type for use in 860766Speter * processing the rest of the 861766Speter * arguments to read. 862766Speter */ 863766Speter file = argv[1]; 864766Speter filetype = ap->type; 865766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 866766Speter putleaf( P2ICON , 0 , 0 867766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 868766Speter , "_UNIT" ); 869766Speter stklval(argv[1], NOFLAGS); 870766Speter putop( P2CALL , P2INT ); 871766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 872766Speter putdot( filename , line ); 873766Speter argv = argv[2]; 874766Speter argc--; 875766Speter } else { 876766Speter /* 877766Speter * Default is read from 878766Speter * standard input. 879766Speter */ 880766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 881766Speter putLV( "_input" , 0 , 0 , P2PTR|P2STRTY ); 882766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 883766Speter putdot( filename , line ); 884766Speter input->nl_flags |= NUSED; 885766Speter } 886766Speter } else { 887766Speter putRV( 0, cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 888766Speter putLV( "_input" , 0 , 0 , P2PTR|P2STRTY ); 889766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 890766Speter putdot( filename , line ); 891766Speter input->nl_flags |= NUSED; 892766Speter } 893766Speter /* 894766Speter * Loop and process each 895766Speter * of the arguments. 896766Speter */ 897766Speter for (; argv != NIL; argv = argv[2]) { 898766Speter /* 899766Speter * Get the address of the target 900766Speter * on the stack. 901766Speter */ 902766Speter al = argv[1]; 903766Speter if (al == NIL) 904766Speter continue; 905766Speter if (al[0] != T_VAR) { 906766Speter error("Arguments to %s must be variables, not expressions", p->symbol); 907766Speter continue; 908766Speter } 909766Speter codeoff(); 910766Speter ap = stklval(al, MOD|ASGN|NOUSE); 911766Speter codeon(); 912766Speter if (ap == NIL) 913766Speter continue; 914766Speter if (filetype != nl+T1CHAR) { 915766Speter /* 916766Speter * Generalized read, i.e. 917766Speter * from a non-textfile. 918766Speter */ 919766Speter if (incompat(filetype, ap, argv[1] )) { 920766Speter error("Type mismatch in read from non-text file"); 921766Speter continue; 922766Speter } 923766Speter /* 924766Speter * var := file ^; 925766Speter */ 926766Speter ap = lvalue( al , MOD | ASGN | NOUSE , RREQ ); 927766Speter if ( isa( ap , "bsci" ) ) { 928766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 929766Speter } 930766Speter putleaf( P2ICON , 0 , 0 931766Speter , ADDTYPE( 932766Speter ADDTYPE( 933766Speter ADDTYPE( 934766Speter p2type( filetype ) , P2PTR ) 935766Speter , P2FTN ) 936766Speter , P2PTR ) 937766Speter , "_FNIL" ); 938766Speter if (file != NIL) 939766Speter stklval(file, NOFLAGS); 940766Speter else /* Magic */ 941766Speter putRV( "_input" , 0 , 0 942766Speter , P2PTR | P2STRTY ); 943766Speter putop( P2CALL , P2INT ); 944766Speter switch ( classify( filetype ) ) { 945766Speter case TBOOL: 946766Speter case TCHAR: 947766Speter case TINT: 948766Speter case TSCAL: 949766Speter case TDOUBLE: 950766Speter case TPTR: 951766Speter putop( P2UNARY P2MUL 952766Speter , p2type( filetype ) ); 953766Speter } 954766Speter switch ( classify( filetype ) ) { 955766Speter case TBOOL: 956766Speter case TCHAR: 957766Speter case TINT: 958766Speter case TSCAL: 959766Speter postcheck( ap ); 960766Speter /* and fall through */ 961766Speter case TDOUBLE: 962766Speter case TPTR: 963766Speter putop( P2ASSIGN , p2type( ap ) ); 964766Speter putdot( filename , line ); 965766Speter break; 966766Speter default: 967766Speter putstrop( P2STASG 968766Speter , p2type( ap ) 969766Speter , lwidth( ap ) 970766Speter , align( ap ) ); 971766Speter putdot( filename , line ); 972766Speter break; 973766Speter } 974766Speter /* 975766Speter * get(file); 976766Speter */ 977766Speter putleaf( P2ICON , 0 , 0 978766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 979766Speter , "_GET" ); 980766Speter putRV( 0 , cbn , CURFILEOFFSET 981766Speter , P2PTR|P2STRTY ); 982766Speter putop( P2CALL , P2INT ); 983766Speter putdot( filename , line ); 984766Speter continue; 985766Speter } 986766Speter /* 987766Speter * if you get to here, you are reading from 988766Speter * a text file. only possiblities are: 989766Speter * character, integer, real, or scalar. 990766Speter * read( f , foo , ... ) is done as 991766Speter * foo := read( f ) with rangechecking 992766Speter * if appropriate. 993766Speter */ 994766Speter typ = classify(ap); 995766Speter op = rdops(typ); 996766Speter if (op == NIL) { 997766Speter error("Can't read %ss from a text file", clnames[typ]); 998766Speter continue; 999766Speter } 1000766Speter /* 1001766Speter * left hand side of foo := read( f ) 1002766Speter */ 1003766Speter ap = lvalue( al , MOD|ASGN|NOUSE , RREQ ); 1004766Speter if ( isa( ap , "bsci" ) ) { 1005766Speter precheck( ap , "_RANG4" , "_RSNG4" ); 1006766Speter } 1007766Speter switch ( op ) { 1008766Speter case O_READC: 1009766Speter readname = "_READC"; 1010766Speter readtype = P2INT; 1011766Speter break; 1012766Speter case O_READ4: 1013766Speter readname = "_READ4"; 1014766Speter readtype = P2INT; 1015766Speter break; 1016766Speter case O_READ8: 1017766Speter readname = "_READ8"; 1018766Speter readtype = P2DOUBLE; 1019766Speter break; 1020766Speter case O_READE: 1021766Speter readname = "_READE"; 1022766Speter readtype = P2INT; 1023766Speter break; 1024766Speter } 1025766Speter putleaf( P2ICON , 0 , 0 1026766Speter , ADDTYPE( P2FTN | readtype , P2PTR ) 1027766Speter , readname ); 1028766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 1029766Speter if ( op == O_READE ) { 1030766Speter sprintf( format , PREFIXFORMAT , LABELPREFIX 1031766Speter , listnames( ap ) ); 1032766Speter putleaf( P2ICON , 0 , 0 , P2PTR | P2CHAR 1033766Speter , format ); 1034766Speter putop( P2LISTOP , P2INT ); 10351629Speter warning(); 1036766Speter if (opt('s')) { 1037766Speter standard(); 1038766Speter } 10391629Speter error("Reading scalars from text files is non-standard"); 1040766Speter } 1041766Speter putop( P2CALL , readtype ); 1042766Speter if ( isa( ap , "bcsi" ) ) { 1043766Speter postcheck( ap ); 1044766Speter } 1045766Speter putop( P2ASSIGN , p2type( ap ) ); 1046766Speter putdot( filename , line ); 1047766Speter } 1048766Speter /* 1049766Speter * Done with arguments. 1050766Speter * Handle readln and 1051766Speter * insufficient number of args. 1052766Speter */ 1053766Speter if (p->value[0] == O_READLN) { 1054766Speter if (filetype != nl+T1CHAR) 1055766Speter error("Can't 'readln' a non text file"); 1056766Speter putleaf( P2ICON , 0 , 0 1057766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1058766Speter , "_READLN" ); 1059766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 1060766Speter putop( P2CALL , P2INT ); 1061766Speter putdot( filename , line ); 1062766Speter } else if (argc == 0) 1063766Speter error("read requires an argument"); 1064766Speter return; 1065766Speter 1066766Speter case O_GET: 1067766Speter case O_PUT: 1068766Speter if (argc != 1) { 1069766Speter error("%s expects one argument", p->symbol); 1070766Speter return; 1071766Speter } 1072766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 1073766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1074766Speter , "_UNIT" ); 1075766Speter ap = stklval(argv[1], NOFLAGS); 1076766Speter if (ap == NIL) 1077766Speter return; 1078766Speter if (ap->class != FILET) { 1079766Speter error("Argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1080766Speter return; 1081766Speter } 1082766Speter putop( P2CALL , P2INT ); 1083766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1084766Speter putdot( filename , line ); 1085766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1086766Speter , op == O_GET ? "_GET" : "_PUT" ); 1087766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 1088766Speter putop( P2CALL , P2INT ); 1089766Speter putdot( filename , line ); 1090766Speter return; 1091766Speter 1092766Speter case O_RESET: 1093766Speter case O_REWRITE: 1094766Speter if (argc == 0 || argc > 2) { 1095766Speter error("%s expects one or two arguments", p->symbol); 1096766Speter return; 1097766Speter } 1098766Speter if (opt('s') && argc == 2) { 1099766Speter standard(); 1100766Speter error("Two argument forms of reset and rewrite are non-standard"); 1101766Speter } 1102766Speter putleaf( P2ICON , 0 , 0 , P2INT 1103766Speter , op == O_RESET ? "_RESET" : "_REWRITE" ); 1104766Speter ap = stklval(argv[1], MOD|NOUSE); 1105766Speter if (ap == NIL) 1106766Speter return; 1107766Speter if (ap->class != FILET) { 1108766Speter error("First argument to %s must be a file, not %s", p->symbol, nameof(ap)); 1109766Speter return; 1110766Speter } 1111766Speter if (argc == 2) { 1112766Speter /* 1113766Speter * Optional second argument 1114766Speter * is a string name of a 1115766Speter * UNIX (R) file to be associated. 1116766Speter */ 1117766Speter al = argv[2]; 1118766Speter al = stkrval(al[1], NOFLAGS , RREQ ); 1119766Speter if (al == NIL) 1120766Speter return; 1121766Speter if (classify(al) != TSTR) { 1122766Speter error("Second argument to %s must be a string, not %s", p->symbol, nameof(al)); 1123766Speter return; 1124766Speter } 1125766Speter strnglen = width(al); 1126766Speter } else { 1127766Speter putleaf( P2ICON , 0 , 0 , P2INT , 0 ); 1128766Speter strnglen = 0; 1129766Speter } 1130766Speter putop( P2LISTOP , P2INT ); 1131766Speter putleaf( P2ICON , strnglen , 0 , P2INT , 0 ); 1132766Speter putop( P2LISTOP , P2INT ); 1133766Speter putleaf( P2ICON , text(ap) ? 0: width(ap->type) , 0 , P2INT , 0 ); 1134766Speter putop( P2LISTOP , P2INT ); 1135766Speter putop( P2CALL , P2INT ); 1136766Speter putdot( filename , line ); 1137766Speter return; 1138766Speter 1139766Speter case O_NEW: 1140766Speter case O_DISPOSE: 1141766Speter if (argc == 0) { 1142766Speter error("%s expects at least one argument", p->symbol); 1143766Speter return; 1144766Speter } 1145766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1146766Speter , op == O_DISPOSE ? "_DISPOSE" : 1147766Speter opt('t') ? "_NEWZ" : "_NEW" ); 1148766Speter ap = stklval(argv[1], op == O_NEW ? ( MOD | NOUSE ) : MOD ); 1149766Speter if (ap == NIL) 1150766Speter return; 1151766Speter if (ap->class != PTR) { 1152766Speter error("(First) argument to %s must be a pointer, not %s", p->symbol, nameof(ap)); 1153766Speter return; 1154766Speter } 1155766Speter ap = ap->type; 1156766Speter if (ap == NIL) 1157766Speter return; 1158766Speter argv = argv[2]; 1159766Speter if (argv != NIL) { 1160766Speter if (ap->class != RECORD) { 1161766Speter error("Record required when specifying variant tags"); 1162766Speter return; 1163766Speter } 1164766Speter for (; argv != NIL; argv = argv[2]) { 1165766Speter if (ap->ptr[NL_VARNT] == NIL) { 1166766Speter error("Too many tag fields"); 1167766Speter return; 1168766Speter } 1169766Speter if (!isconst(argv[1])) { 1170766Speter error("Second and successive arguments to %s must be constants", p->symbol); 1171766Speter return; 1172766Speter } 1173766Speter gconst(argv[1]); 1174766Speter if (con.ctype == NIL) 1175766Speter return; 1176766Speter if (incompat(con.ctype, (ap->ptr[NL_TAG])->type , NIL )) { 1177766Speter cerror("Specified tag constant type clashed with variant case selector type"); 1178766Speter return; 1179766Speter } 1180766Speter for (ap = ap->ptr[NL_VARNT]; ap != NIL; ap = ap->chain) 1181766Speter if (ap->range[0] == con.crval) 1182766Speter break; 1183766Speter if (ap == NIL) { 1184766Speter error("No variant case label value equals specified constant value"); 1185766Speter return; 1186766Speter } 1187766Speter ap = ap->ptr[NL_VTOREC]; 1188766Speter } 1189766Speter } 1190766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1191766Speter putop( P2LISTOP , P2INT ); 1192766Speter putop( P2CALL , P2INT ); 1193766Speter putdot( filename , line ); 1194766Speter return; 1195766Speter 1196766Speter case O_DATE: 1197766Speter case O_TIME: 1198766Speter if (argc != 1) { 1199766Speter error("%s expects one argument", p->symbol); 1200766Speter return; 1201766Speter } 1202766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1203766Speter , op == O_DATE ? "_DATE" : "_TIME" ); 1204766Speter ap = stklval(argv[1], MOD|NOUSE); 1205766Speter if (ap == NIL) 1206766Speter return; 1207766Speter if (classify(ap) != TSTR || width(ap) != 10) { 1208766Speter error("Argument to %s must be a alfa, not %s", p->symbol, nameof(ap)); 1209766Speter return; 1210766Speter } 1211766Speter putop( P2CALL , P2INT ); 1212766Speter putdot( filename , line ); 1213766Speter return; 1214766Speter 1215766Speter case O_HALT: 1216766Speter if (argc != 0) { 1217766Speter error("halt takes no arguments"); 1218766Speter return; 1219766Speter } 1220766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1221766Speter , "_HALT" ); 1222766Speter 1223766Speter putop( P2UNARY P2CALL , P2INT ); 1224766Speter putdot( filename , line ); 1225766Speter noreach = 1; 1226766Speter return; 1227766Speter 1228766Speter case O_ARGV: 1229766Speter if (argc != 2) { 1230766Speter error("argv takes two arguments"); 1231766Speter return; 1232766Speter } 1233766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1234766Speter , "_ARGV" ); 1235766Speter ap = stkrval(argv[1], NIL , RREQ ); 1236766Speter if (ap == NIL) 1237766Speter return; 1238766Speter if (isnta(ap, "i")) { 1239766Speter error("argv's first argument must be an integer, not %s", nameof(ap)); 1240766Speter return; 1241766Speter } 1242766Speter al = argv[2]; 1243766Speter ap = stklval(al[1], MOD|NOUSE); 1244766Speter if (ap == NIL) 1245766Speter return; 1246766Speter if (classify(ap) != TSTR) { 1247766Speter error("argv's second argument must be a string, not %s", nameof(ap)); 1248766Speter return; 1249766Speter } 1250766Speter putop( P2LISTOP , P2INT ); 1251766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1252766Speter putop( P2LISTOP , P2INT ); 1253766Speter putop( P2CALL , P2INT ); 1254766Speter putdot( filename , line ); 1255766Speter return; 1256766Speter 1257766Speter case O_STLIM: 1258766Speter if (argc != 1) { 1259766Speter error("stlimit requires one argument"); 1260766Speter return; 1261766Speter } 1262766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1263766Speter , "_STLIM" ); 1264766Speter ap = stkrval(argv[1], NIL , RREQ ); 1265766Speter if (ap == NIL) 1266766Speter return; 1267766Speter if (isnta(ap, "i")) { 1268766Speter error("stlimit's argument must be an integer, not %s", nameof(ap)); 1269766Speter return; 1270766Speter } 1271766Speter putop( P2CALL , P2INT ); 1272766Speter putdot( filename , line ); 1273766Speter return; 1274766Speter 1275766Speter case O_REMOVE: 1276766Speter if (argc != 1) { 1277766Speter error("remove expects one argument"); 1278766Speter return; 1279766Speter } 1280766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1281766Speter , "_REMOVE" ); 1282766Speter ap = stkrval(argv[1], NOFLAGS , RREQ ); 1283766Speter if (ap == NIL) 1284766Speter return; 1285766Speter if (classify(ap) != TSTR) { 1286766Speter error("remove's argument must be a string, not %s", nameof(ap)); 1287766Speter return; 1288766Speter } 1289766Speter putleaf( P2ICON , width( ap ) , 0 , P2INT , 0 ); 1290766Speter putop( P2LISTOP , P2INT ); 1291766Speter putop( P2CALL , P2INT ); 1292766Speter putdot( filename , line ); 1293766Speter return; 1294766Speter 1295766Speter case O_LLIMIT: 1296766Speter if (argc != 2) { 1297766Speter error("linelimit expects two arguments"); 1298766Speter return; 1299766Speter } 1300766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1301766Speter , "_LLIMIT" ); 1302766Speter ap = stklval(argv[1], NOFLAGS|NOUSE); 1303766Speter if (ap == NIL) 1304766Speter return; 1305766Speter if (!text(ap)) { 1306766Speter error("linelimit's first argument must be a text file, not %s", nameof(ap)); 1307766Speter return; 1308766Speter } 1309766Speter al = argv[2]; 1310766Speter ap = stkrval(al[1], NIL , RREQ ); 1311766Speter if (ap == NIL) 1312766Speter return; 1313766Speter if (isnta(ap, "i")) { 1314766Speter error("linelimit's second argument must be an integer, not %s", nameof(ap)); 1315766Speter return; 1316766Speter } 1317766Speter putop( P2LISTOP , P2INT ); 1318766Speter putop( P2CALL , P2INT ); 1319766Speter putdot( filename , line ); 1320766Speter return; 1321766Speter case O_PAGE: 1322766Speter if (argc != 1) { 1323766Speter error("page expects one argument"); 1324766Speter return; 1325766Speter } 1326766Speter putRV( 0 , cbn , CURFILEOFFSET , P2PTR|P2STRTY ); 1327766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1328766Speter , "_UNIT" ); 1329766Speter ap = stklval(argv[1], NOFLAGS); 1330766Speter if (ap == NIL) 1331766Speter return; 1332766Speter if (!text(ap)) { 1333766Speter error("Argument to page must be a text file, not %s", nameof(ap)); 1334766Speter return; 1335766Speter } 1336766Speter putop( P2CALL , P2INT ); 1337766Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 1338766Speter putdot( filename , line ); 1339766Speter if ( opt( 't' ) ) { 1340766Speter putleaf( P2ICON , 0 , 0 1341766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1342766Speter , "_PAGE" ); 1343766Speter putRV( 0 , cbn , CURFILEOFFSET 1344766Speter , P2PTR|P2STRTY ); 1345766Speter } else { 1346766Speter putleaf( P2ICON , 0 , 0 1347766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1348766Speter , "_fputc" ); 1349766Speter putleaf( P2ICON , '\f' , 0 , P2CHAR , 0 ); 1350766Speter putleaf( P2ICON , 0 , 0 1351766Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) 1352766Speter , "_ACTFILE" ); 1353766Speter putRV( 0 , cbn , CURFILEOFFSET 1354766Speter , P2PTR|P2STRTY ); 1355766Speter putop( P2CALL , P2INT ); 1356766Speter putop( P2LISTOP , P2INT ); 1357766Speter } 1358766Speter putop( P2CALL , P2INT ); 1359766Speter putdot( filename , line ); 1360766Speter return; 1361766Speter 1362766Speter case O_PACK: 1363766Speter if (argc != 3) { 1364766Speter error("pack expects three arguments"); 1365766Speter return; 1366766Speter } 1367766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1368766Speter , "_PACK" ); 1369766Speter pu = "pack(a,i,z)"; 1370766Speter pua = (al = argv)[1]; 1371766Speter pui = (al = al[2])[1]; 1372766Speter puz = (al = al[2])[1]; 1373766Speter goto packunp; 1374766Speter case O_UNPACK: 1375766Speter if (argc != 3) { 1376766Speter error("unpack expects three arguments"); 1377766Speter return; 1378766Speter } 1379766Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 1380766Speter , "_UNPACK" ); 1381766Speter pu = "unpack(z,a,i)"; 1382766Speter puz = (al = argv)[1]; 1383766Speter pua = (al = al[2])[1]; 1384766Speter pui = (al = al[2])[1]; 1385766Speter packunp: 1386766Speter ap = stkrval((int *) pui, NLNIL , RREQ ); 1387766Speter if (ap == NIL) 1388766Speter return; 1389766Speter ap = stklval(pua, op == O_PACK ? NOFLAGS : MOD|NOUSE); 1390766Speter if (ap == NIL) 1391766Speter return; 1392766Speter if (ap->class != ARRAY) { 1393766Speter error("%s requires a to be an unpacked array, not %s", pu, nameof(ap)); 1394766Speter return; 1395766Speter } 1396766Speter putop( P2LISTOP , P2INT ); 1397766Speter al = (struct nl *) stklval(puz, op == O_UNPACK ? NOFLAGS : MOD|NOUSE); 1398766Speter if (al->class != ARRAY) { 1399766Speter error("%s requires z to be a packed array, not %s", pu, nameof(ap)); 1400766Speter return; 1401766Speter } 1402766Speter if (al->type == NIL || ap->type == NIL) 1403766Speter return; 1404766Speter if (al->type != ap->type) { 1405766Speter error("%s requires a and z to be arrays of the same type", pu, nameof(ap)); 1406766Speter return; 1407766Speter } 1408766Speter putop( P2LISTOP , P2INT ); 1409766Speter k = width(al); 1410766Speter itemwidth = width(ap->type); 1411766Speter ap = ap->chain; 1412766Speter al = al->chain; 1413766Speter if (ap->chain != NIL || al->chain != NIL) { 1414766Speter error("%s requires a and z to be single dimension arrays", pu); 1415766Speter return; 1416766Speter } 1417766Speter if (ap == NIL || al == NIL) 1418766Speter return; 1419766Speter /* 1420766Speter * al is the range for z i.e. u..v 1421766Speter * ap is the range for a i.e. m..n 1422766Speter * i will be n-m+1 1423766Speter * j will be v-u+1 1424766Speter */ 1425766Speter i = ap->range[1] - ap->range[0] + 1; 1426766Speter j = al->range[1] - al->range[0] + 1; 1427766Speter if (i < j) { 1428766Speter error("%s cannot have more elements in a (%d) than in z (%d)", pu, j, i); 1429766Speter return; 1430766Speter } 1431766Speter /* 1432766Speter * get n-m-(v-u) and m for the interpreter 1433766Speter */ 1434766Speter i -= j; 1435766Speter j = ap->range[0]; 1436766Speter putleaf( P2ICON , itemwidth , 0 , P2INT , 0 ); 1437766Speter putop( P2LISTOP , P2INT ); 1438766Speter putleaf( P2ICON , j , 0 , P2INT , 0 ); 1439766Speter putop( P2LISTOP , P2INT ); 1440766Speter putleaf( P2ICON , i , 0 , P2INT , 0 ); 1441766Speter putop( P2LISTOP , P2INT ); 1442766Speter putleaf( P2ICON , k , 0 , P2INT , 0 ); 1443766Speter putop( P2LISTOP , P2INT ); 1444766Speter putop( P2CALL , P2INT ); 1445766Speter putdot( filename , line ); 1446766Speter return; 1447766Speter case 0: 1448766Speter error("%s is an unimplemented 6400 extension", p->symbol); 1449766Speter return; 1450766Speter 1451766Speter default: 1452766Speter panic("proc case"); 1453766Speter } 1454766Speter } 1455766Speter #endif PC 1456