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