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