1773Speter /* Copyright (c) 1979 Regents of the University of California */ 2773Speter 3*2185Smckusic static char sccsid[] = "@(#)stat.c 1.2 01/16/81"; 4773Speter 5773Speter #include "whoami.h" 6773Speter #include "0.h" 7773Speter #include "tree.h" 8773Speter #include "objfmt.h" 9773Speter #ifdef PC 10773Speter # include "pcops.h" 11773Speter # include "pc.h" 12773Speter #endif PC 13773Speter 14773Speter int cntstat; 15773Speter short cnts = 3; 16773Speter #include "opcode.h" 17773Speter 18773Speter /* 19773Speter * Statement list 20773Speter */ 21773Speter statlist(r) 22773Speter int *r; 23773Speter { 24773Speter register *sl; 25773Speter 26773Speter for (sl=r; sl != NIL; sl=sl[2]) 27773Speter statement(sl[1]); 28773Speter } 29773Speter 30773Speter /* 31773Speter * Statement 32773Speter */ 33773Speter statement(r) 34773Speter int *r; 35773Speter { 36773Speter register *s; 37773Speter register struct nl *snlp; 38773Speter long soffset; 39773Speter 40773Speter s = r; 41773Speter snlp = nlp; 42773Speter soffset = sizes[ cbn ].om_off; 43773Speter top: 44773Speter if (cntstat) { 45773Speter cntstat = 0; 46773Speter putcnt(); 47773Speter } 48773Speter if (s == NIL) 49773Speter return; 50773Speter line = s[1]; 51773Speter if (s[0] == T_LABEL) { 52773Speter labeled(s[2]); 53773Speter s = s[3]; 54773Speter noreach = 0; 55773Speter cntstat = 1; 56773Speter goto top; 57773Speter } 58773Speter if (noreach) { 59773Speter noreach = 0; 60773Speter warning(); 61773Speter error("Unreachable statement"); 62773Speter } 63773Speter switch (s[0]) { 64773Speter case T_PCALL: 65773Speter putline(); 66773Speter # ifdef OBJ 67773Speter proc(s); 68773Speter # endif OBJ 69773Speter # ifdef PC 70773Speter pcproc( s ); 71773Speter # endif PC 72773Speter break; 73773Speter case T_ASGN: 74773Speter putline(); 75773Speter asgnop(s); 76773Speter break; 77773Speter case T_GOTO: 78773Speter putline(); 79773Speter gotoop(s[2]); 80773Speter noreach = 1; 81773Speter cntstat = 1; 82773Speter break; 83773Speter default: 84773Speter level++; 85773Speter switch (s[0]) { 86773Speter default: 87773Speter panic("stat"); 88773Speter case T_IF: 89773Speter case T_IFEL: 90773Speter ifop(s); 91773Speter break; 92773Speter case T_WHILE: 93773Speter whilop(s); 94773Speter noreach = 0; 95773Speter break; 96773Speter case T_REPEAT: 97773Speter repop(s); 98773Speter break; 99773Speter case T_FORU: 100773Speter case T_FORD: 101*2185Smckusic forop(s); 102773Speter noreach = 0; 103773Speter break; 104773Speter case T_BLOCK: 105773Speter statlist(s[2]); 106773Speter break; 107773Speter case T_CASE: 108773Speter putline(); 109773Speter # ifdef OBJ 110773Speter caseop(s); 111773Speter # endif OBJ 112773Speter # ifdef PC 113773Speter pccaseop( s ); 114773Speter # endif PC 115773Speter break; 116773Speter case T_WITH: 117773Speter withop(s); 118773Speter break; 119773Speter case T_ASRT: 120773Speter putline(); 121773Speter asrtop(s); 122773Speter break; 123773Speter } 124773Speter --level; 125773Speter if (gotos[cbn]) 126773Speter ungoto(); 127773Speter break; 128773Speter } 129773Speter /* 130773Speter * Free the temporary name list entries defined in 131773Speter * expressions, e.g. STRs, and WITHPTRs from withs. 132773Speter */ 133773Speter nlfree(snlp); 134773Speter /* 135773Speter * free any temporaries allocated for this statement 136773Speter * these come from strings and sets. 137773Speter */ 138773Speter if ( soffset != sizes[ cbn ].om_off ) { 139773Speter sizes[ cbn ].om_off = soffset; 140773Speter # ifdef PC 141773Speter putlbracket( ftnno , -sizes[cbn].om_off ); 142773Speter # endif PC 143773Speter } 144773Speter } 145773Speter 146773Speter ungoto() 147773Speter { 148773Speter register struct nl *p; 149773Speter 150773Speter for (p = gotos[cbn]; p != NIL; p = p->chain) 151773Speter if ((p->nl_flags & NFORWD) != 0) { 152773Speter if (p->value[NL_GOLEV] != NOTYET) 153773Speter if (p->value[NL_GOLEV] > level) 154773Speter p->value[NL_GOLEV] = level; 155773Speter } else 156773Speter if (p->value[NL_GOLEV] != DEAD) 157773Speter if (p->value[NL_GOLEV] > level) 158773Speter p->value[NL_GOLEV] = DEAD; 159773Speter } 160773Speter 161773Speter putcnt() 162773Speter { 163773Speter 164773Speter if (monflg == 0) { 165773Speter return; 166773Speter } 167773Speter inccnt( getcnt() ); 168773Speter } 169773Speter 170773Speter int 171773Speter getcnt() 172773Speter { 173773Speter 174773Speter return ++cnts; 175773Speter } 176773Speter 177773Speter inccnt( counter ) 178773Speter int counter; 179773Speter { 180773Speter 181773Speter # ifdef OBJ 182773Speter put2(O_COUNT, counter ); 183773Speter # endif OBJ 184773Speter # ifdef PC 185773Speter putRV( PCPCOUNT , 0 , counter * sizeof (long) , P2INT ); 186773Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 187773Speter putop( P2ASG P2PLUS , P2INT ); 188773Speter putdot( filename , line ); 189773Speter # endif PC 190773Speter } 191773Speter 192773Speter putline() 193773Speter { 194773Speter 195773Speter # ifdef OBJ 196773Speter if (opt('p') != 0) 197773Speter put2(O_LINO, line); 198773Speter # endif OBJ 199773Speter # ifdef PC 200773Speter static lastline; 201773Speter 202773Speter if ( line != lastline ) { 203773Speter stabline( line ); 204773Speter lastline = line; 205773Speter } 206773Speter if ( opt( 'p' ) ) { 207773Speter if ( opt('t') ) { 208773Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 209773Speter , "_LINO" ); 210773Speter putop( P2UNARY P2CALL , P2INT ); 211773Speter putdot( filename , line ); 212773Speter } else { 213773Speter putRV( STMTCOUNT , 0 , 0 , P2INT ); 214773Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 215773Speter putop( P2ASG P2PLUS , P2INT ); 216773Speter putdot( filename , line ); 217773Speter } 218773Speter } 219773Speter # endif PC 220773Speter } 221773Speter 222773Speter /* 223773Speter * With varlist do stat 224773Speter * 225773Speter * With statement requires an extra word 226773Speter * in automatic storage for each level of withing. 227773Speter * These indirect pointers are initialized here, and 228773Speter * the scoping effect of the with statement occurs 229773Speter * because lookup examines the field names of the records 230773Speter * associated with the WITHPTRs on the withlist. 231773Speter */ 232773Speter withop(s) 233773Speter int *s; 234773Speter { 235773Speter register *p; 236773Speter register struct nl *r; 237773Speter int i; 238773Speter int *swl; 239773Speter long soffset; 240773Speter 241773Speter putline(); 242773Speter swl = withlist; 243773Speter soffset = sizes[cbn].om_off; 244773Speter for (p = s[2]; p != NIL; p = p[2]) { 245773Speter i = sizes[cbn].om_off -= sizeof ( int * ); 246773Speter if (sizes[cbn].om_off < sizes[cbn].om_max) 247773Speter sizes[cbn].om_max = sizes[cbn].om_off; 248773Speter # ifdef OBJ 249773Speter put2(O_LV | cbn <<8+INDX, i ); 250773Speter # endif OBJ 251773Speter # ifdef PC 252773Speter putlbracket( ftnno , -sizes[cbn].om_off ); 253773Speter putRV( 0 , cbn , i , P2PTR|P2STRTY ); 254773Speter # endif PC 255773Speter r = lvalue(p[1], MOD , LREQ ); 256773Speter if (r == NIL) 257773Speter continue; 258773Speter if (r->class != RECORD) { 259773Speter error("Variable in with statement refers to %s, not to a record", nameof(r)); 260773Speter continue; 261773Speter } 262773Speter r = defnl(0, WITHPTR, r, i); 263773Speter r->nl_next = withlist; 264773Speter withlist = r; 265773Speter # ifdef OBJ 266773Speter put(1, PTR_AS); 267773Speter # endif OBJ 268773Speter # ifdef PC 269773Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 270773Speter putdot( filename , line ); 271773Speter # endif PC 272773Speter } 273773Speter statement(s[3]); 274773Speter sizes[cbn].om_off = soffset; 275773Speter # ifdef PC 276773Speter putlbracket( ftnno , -sizes[cbn].om_off ); 277773Speter # endif PC 278773Speter withlist = swl; 279773Speter } 280773Speter 281773Speter extern flagwas; 282773Speter /* 283773Speter * var := expr 284773Speter */ 285773Speter asgnop(r) 286773Speter int *r; 287773Speter { 288773Speter register struct nl *p; 289773Speter register *av; 290773Speter 291773Speter if (r == NIL) 292773Speter return (NIL); 293773Speter /* 294773Speter * Asgnop's only function is 295773Speter * to handle function variable 296773Speter * assignments. All other assignment 297773Speter * stuff is handled by asgnop1. 298773Speter * the if below checks for unqualified lefthandside: 299773Speter * necessary for fvars. 300773Speter */ 301773Speter av = r[2]; 302773Speter if (av != NIL && av[0] == T_VAR && av[3] == NIL) { 303773Speter p = lookup1(av[2]); 304773Speter if (p != NIL) 305773Speter p->nl_flags = flagwas; 306773Speter if (p != NIL && p->class == FVAR) { 307773Speter /* 308773Speter * Give asgnop1 the func 309773Speter * which is the chain of 310773Speter * the FVAR. 311773Speter */ 312773Speter p->nl_flags |= NUSED|NMOD; 313773Speter p = p->chain; 314773Speter if (p == NIL) { 315773Speter rvalue(r[3], NIL , RREQ ); 316773Speter return; 317773Speter } 318773Speter # ifdef OBJ 319773Speter put2(O_LV | bn << 8+INDX, p->value[NL_OFFS]); 320773Speter if (isa(p->type, "i") && width(p->type) == 1) 321773Speter asgnop1(r, nl+T2INT); 322773Speter else 323773Speter asgnop1(r, p->type); 324773Speter # endif OBJ 325773Speter # ifdef PC 326773Speter /* 327773Speter * this should be the lvalue of the fvar, 328773Speter * but since the second pass knows to use 329773Speter * the address of the left operand of an 330773Speter * assignment, what i want here is an rvalue. 331773Speter * see note in funchdr about fvar allocation. 332773Speter */ 333773Speter p = p -> ptr[ NL_FVAR ]; 334773Speter putRV( p -> symbol , bn , p -> value[ NL_OFFS ] 335773Speter , p2type( p -> type ) ); 336773Speter asgnop1( r , p -> type ); 337773Speter # endif PC 338773Speter return; 339773Speter } 340773Speter } 341773Speter asgnop1(r, NIL); 342773Speter } 343773Speter 344773Speter /* 345773Speter * Asgnop1 handles all assignments. 346773Speter * If p is not nil then we are assigning 347773Speter * to a function variable, otherwise 348773Speter * we look the variable up ourselves. 349773Speter */ 350773Speter struct nl * 351773Speter asgnop1(r, p) 352773Speter int *r; 353773Speter register struct nl *p; 354773Speter { 355773Speter register struct nl *p1; 356773Speter 357773Speter if (r == NIL) 358773Speter return (NIL); 359773Speter if (p == NIL) { 360773Speter # ifdef OBJ 361773Speter p = lvalue(r[2], MOD|ASGN|NOUSE , LREQ ); 362773Speter # endif OBJ 363773Speter # ifdef PC 364773Speter /* 365773Speter * since the second pass knows that it should reference 366773Speter * the lefthandside of asignments, what i need here is 367773Speter * an rvalue. 368773Speter */ 369773Speter p = lvalue( r[2] , MOD|ASGN|NOUSE , RREQ ); 370773Speter # endif PC 371773Speter if ( p == NIL ) { 372773Speter rvalue( r[3] , NIL , RREQ ); 373773Speter return NIL; 374773Speter } 375773Speter } 376773Speter # ifdef OBJ 377773Speter p1 = rvalue(r[3], p , RREQ ); 378773Speter # endif OBJ 379773Speter # ifdef PC 380773Speter /* 381773Speter * if this is a scalar assignment, 382773Speter * then i want to rvalue the righthandside. 383773Speter * if this is a structure assignment, 384773Speter * then i want an lvalue to the righthandside. 385773Speter * that's what the intermediate form sez. 386773Speter */ 387773Speter switch ( classify( p ) ) { 388773Speter case TINT: 389773Speter case TCHAR: 390773Speter case TBOOL: 391773Speter case TSCAL: 392773Speter precheck( p , "_RANG4" , "_RSNG4" ); 393773Speter case TDOUBLE: 394773Speter case TPTR: 395773Speter p1 = rvalue( r[3] , p , RREQ ); 396773Speter break; 397773Speter default: 398773Speter p1 = rvalue( r[3] , p , LREQ ); 399773Speter break; 400773Speter } 401773Speter # endif PC 402773Speter if (p1 == NIL) 403773Speter return (NIL); 404773Speter if (incompat(p1, p, r[3])) { 405773Speter cerror("Type of expression clashed with type of variable in assignment"); 406773Speter return (NIL); 407773Speter } 408773Speter switch (classify(p)) { 409773Speter case TINT: 410773Speter case TBOOL: 411773Speter case TCHAR: 412773Speter case TSCAL: 413773Speter # ifdef OBJ 414773Speter rangechk(p, p1); 415773Speter # endif OBJ 416773Speter # ifdef PC 417773Speter postcheck( p ); 418773Speter # endif PC 419773Speter case TDOUBLE: 420773Speter case TPTR: 421773Speter # ifdef OBJ 422773Speter gen(O_AS2, O_AS2, width(p), width(p1)); 423773Speter # endif OBJ 424773Speter # ifdef PC 425773Speter putop( P2ASSIGN , p2type( p ) ); 426773Speter putdot( filename , line ); 427773Speter # endif PC 428773Speter break; 429773Speter default: 430773Speter # ifdef OBJ 431773Speter put2(O_AS, width(p)); 432773Speter # endif OBJ 433773Speter # ifdef PC 434773Speter putstrop( P2STASG , p2type( p ) 435773Speter , lwidth( p ) , align( p ) ); 436773Speter putdot( filename , line ); 437773Speter # endif PC 438773Speter } 439773Speter return (p); /* Used by for statement */ 440773Speter } 441773Speter 442773Speter /* 443773Speter * if expr then stat [ else stat ] 444773Speter */ 445773Speter ifop(r) 446773Speter int *r; 447773Speter { 448773Speter register struct nl *p; 449773Speter register l1, l2; /* l1 is start of else, l2 is end of else */ 450773Speter int nr, goc; 451773Speter 452773Speter goc = gocnt; 453773Speter if (r == NIL) 454773Speter return; 455773Speter putline(); 456773Speter p = rvalue(r[2], NIL , RREQ ); 457773Speter if (p == NIL) { 458773Speter statement(r[3]); 459773Speter noreach = 0; 460773Speter statement(r[4]); 461773Speter noreach = 0; 462773Speter return; 463773Speter } 464773Speter if (isnta(p, "b")) { 465773Speter error("Type of expression in if statement must be Boolean, not %s", nameof(p)); 466773Speter statement(r[3]); 467773Speter noreach = 0; 468773Speter statement(r[4]); 469773Speter noreach = 0; 470773Speter return; 471773Speter } 472773Speter # ifdef OBJ 473773Speter l1 = put2(O_IF, getlab()); 474773Speter # endif OBJ 475773Speter # ifdef PC 476773Speter l1 = getlab(); 477773Speter putleaf( P2ICON , l1 , 0 , P2INT , 0 ); 478773Speter putop( P2CBRANCH , P2INT ); 479773Speter putdot( filename , line ); 480773Speter # endif PC 481773Speter putcnt(); 482773Speter statement(r[3]); 483773Speter nr = noreach; 484773Speter if (r[4] != NIL) { 485773Speter /* 486773Speter * else stat 487773Speter */ 488773Speter --level; 489773Speter ungoto(); 490773Speter ++level; 491773Speter # ifdef OBJ 492773Speter l2 = put2(O_TRA, getlab()); 493773Speter # endif OBJ 494773Speter # ifdef PC 495773Speter l2 = getlab(); 496773Speter putjbr( l2 ); 497773Speter # endif PC 498773Speter patch(l1); 499773Speter noreach = 0; 500773Speter statement(r[4]); 501773Speter noreach &= nr; 502773Speter l1 = l2; 503773Speter } else 504773Speter noreach = 0; 505773Speter patch(l1); 506773Speter if (goc != gocnt) 507773Speter putcnt(); 508773Speter } 509773Speter 510773Speter /* 511773Speter * while expr do stat 512773Speter */ 513773Speter whilop(r) 514773Speter int *r; 515773Speter { 516773Speter register struct nl *p; 517773Speter register l1, l2; 518773Speter int goc; 519773Speter 520773Speter goc = gocnt; 521773Speter if (r == NIL) 522773Speter return; 523773Speter putlab(l1 = getlab()); 524773Speter putline(); 525773Speter p = rvalue(r[2], NIL , RREQ ); 526773Speter if (p == NIL) { 527773Speter statement(r[3]); 528773Speter noreach = 0; 529773Speter return; 530773Speter } 531773Speter if (isnta(p, "b")) { 532773Speter error("Type of expression in while statement must be Boolean, not %s", nameof(p)); 533773Speter statement(r[3]); 534773Speter noreach = 0; 535773Speter return; 536773Speter } 537773Speter l2 = getlab(); 538773Speter # ifdef OBJ 539773Speter put2(O_IF, l2); 540773Speter # endif OBJ 541773Speter # ifdef PC 542773Speter putleaf( P2ICON , l2 , 0 , P2INT , 0 ); 543773Speter putop( P2CBRANCH , P2INT ); 544773Speter putdot( filename , line ); 545773Speter # endif PC 546773Speter putcnt(); 547773Speter statement(r[3]); 548773Speter # ifdef OBJ 549773Speter put2(O_TRA, l1); 550773Speter # endif OBJ 551773Speter # ifdef PC 552773Speter putjbr( l1 ); 553773Speter # endif PC 554773Speter patch(l2); 555773Speter if (goc != gocnt) 556773Speter putcnt(); 557773Speter } 558773Speter 559773Speter /* 560773Speter * repeat stat* until expr 561773Speter */ 562773Speter repop(r) 563773Speter int *r; 564773Speter { 565773Speter register struct nl *p; 566773Speter register l; 567773Speter int goc; 568773Speter 569773Speter goc = gocnt; 570773Speter if (r == NIL) 571773Speter return; 572773Speter l = putlab(getlab()); 573773Speter putcnt(); 574773Speter statlist(r[2]); 575773Speter line = r[1]; 576773Speter p = rvalue(r[3], NIL , RREQ ); 577773Speter if (p == NIL) 578773Speter return; 579773Speter if (isnta(p,"b")) { 580773Speter error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p)); 581773Speter return; 582773Speter } 583773Speter # ifdef OBJ 584773Speter put2(O_IF, l); 585773Speter # endif OBJ 586773Speter # ifdef PC 587773Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 588773Speter putop( P2CBRANCH , P2INT ); 589773Speter putdot( filename , line ); 590773Speter # endif PC 591773Speter if (goc != gocnt) 592773Speter putcnt(); 593773Speter } 594773Speter 595773Speter /* 596773Speter * assert expr 597773Speter */ 598773Speter asrtop(r) 599773Speter register int *r; 600773Speter { 601773Speter register struct nl *q; 602773Speter 603773Speter if (opt('s')) { 604773Speter standard(); 605773Speter error("Assert statement is non-standard"); 606773Speter } 607773Speter if (!opt('t')) 608773Speter return; 609773Speter r = r[2]; 610773Speter # ifdef OBJ 611773Speter q = rvalue((int *) r, NLNIL , RREQ ); 612773Speter # endif OBJ 613773Speter # ifdef PC 614773Speter putleaf( P2ICON , 0 , 0 615773Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ASRT" ); 616773Speter q = stkrval( r , NLNIL , RREQ ); 617773Speter # endif PC 618773Speter if (q == NIL) 619773Speter return; 620773Speter if (isnta(q, "b")) 621773Speter error("Assert expression must be Boolean, not %ss", nameof(q)); 622773Speter # ifdef OBJ 623773Speter put1(O_ASRT); 624773Speter # endif OBJ 625773Speter # ifdef PC 626773Speter putop( P2CALL , P2INT ); 627773Speter putdot( filename , line ); 628773Speter # endif PC 629773Speter } 630