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