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