1773Speter /* Copyright (c) 1979 Regents of the University of California */ 2773Speter 3*3228Smckusic static char sccsid[] = "@(#)stat.c 1.4 03/11/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; 38*3228Smckusic struct tmps soffset; 39773Speter 40773Speter s = r; 41773Speter snlp = nlp; 42*3228Smckusic soffset = sizes[cbn].curtmps; 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: 1012185Smckusic 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 */ 138*3228Smckusic tmpfree(&soffset); 139773Speter } 140773Speter 141773Speter ungoto() 142773Speter { 143773Speter register struct nl *p; 144773Speter 145773Speter for (p = gotos[cbn]; p != NIL; p = p->chain) 146773Speter if ((p->nl_flags & NFORWD) != 0) { 147773Speter if (p->value[NL_GOLEV] != NOTYET) 148773Speter if (p->value[NL_GOLEV] > level) 149773Speter p->value[NL_GOLEV] = level; 150773Speter } else 151773Speter if (p->value[NL_GOLEV] != DEAD) 152773Speter if (p->value[NL_GOLEV] > level) 153773Speter p->value[NL_GOLEV] = DEAD; 154773Speter } 155773Speter 156773Speter putcnt() 157773Speter { 158773Speter 159773Speter if (monflg == 0) { 160773Speter return; 161773Speter } 162773Speter inccnt( getcnt() ); 163773Speter } 164773Speter 165773Speter int 166773Speter getcnt() 167773Speter { 168773Speter 169773Speter return ++cnts; 170773Speter } 171773Speter 172773Speter inccnt( counter ) 173773Speter int counter; 174773Speter { 175773Speter 176773Speter # ifdef OBJ 1773079Smckusic put(2, O_COUNT, counter ); 178773Speter # endif OBJ 179773Speter # ifdef PC 180773Speter putRV( PCPCOUNT , 0 , counter * sizeof (long) , P2INT ); 181773Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 182773Speter putop( P2ASG P2PLUS , P2INT ); 183773Speter putdot( filename , line ); 184773Speter # endif PC 185773Speter } 186773Speter 187773Speter putline() 188773Speter { 189773Speter 190773Speter # ifdef OBJ 191773Speter if (opt('p') != 0) 1923079Smckusic put(2, O_LINO, line); 193773Speter # endif OBJ 194773Speter # ifdef PC 195773Speter static lastline; 196773Speter 197773Speter if ( line != lastline ) { 198773Speter stabline( line ); 199773Speter lastline = line; 200773Speter } 201773Speter if ( opt( 'p' ) ) { 202773Speter if ( opt('t') ) { 203773Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 204773Speter , "_LINO" ); 205773Speter putop( P2UNARY P2CALL , P2INT ); 206773Speter putdot( filename , line ); 207773Speter } else { 208773Speter putRV( STMTCOUNT , 0 , 0 , P2INT ); 209773Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 210773Speter putop( P2ASG P2PLUS , P2INT ); 211773Speter putdot( filename , line ); 212773Speter } 213773Speter } 214773Speter # endif PC 215773Speter } 216773Speter 217773Speter /* 218773Speter * With varlist do stat 219773Speter * 220773Speter * With statement requires an extra word 221773Speter * in automatic storage for each level of withing. 222773Speter * These indirect pointers are initialized here, and 223773Speter * the scoping effect of the with statement occurs 224773Speter * because lookup examines the field names of the records 225773Speter * associated with the WITHPTRs on the withlist. 226773Speter */ 227773Speter withop(s) 228773Speter int *s; 229773Speter { 230773Speter register *p; 231773Speter register struct nl *r; 232773Speter int i; 233773Speter int *swl; 234773Speter 235773Speter putline(); 236773Speter swl = withlist; 237773Speter for (p = s[2]; p != NIL; p = p[2]) { 238*3228Smckusic i = tmpalloc(sizeof(int *), INT_TYP, REGOK); 239773Speter # ifdef OBJ 2403079Smckusic put(2, O_LV | cbn <<8+INDX, i ); 241773Speter # endif OBJ 242773Speter # ifdef PC 243773Speter putRV( 0 , cbn , i , P2PTR|P2STRTY ); 244773Speter # endif PC 245773Speter r = lvalue(p[1], MOD , LREQ ); 246773Speter if (r == NIL) 247773Speter continue; 248773Speter if (r->class != RECORD) { 249773Speter error("Variable in with statement refers to %s, not to a record", nameof(r)); 250773Speter continue; 251773Speter } 252773Speter r = defnl(0, WITHPTR, r, i); 253773Speter r->nl_next = withlist; 254773Speter withlist = r; 255773Speter # ifdef OBJ 256773Speter put(1, PTR_AS); 257773Speter # endif OBJ 258773Speter # ifdef PC 259773Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 260773Speter putdot( filename , line ); 261773Speter # endif PC 262773Speter } 263773Speter statement(s[3]); 264773Speter withlist = swl; 265773Speter } 266773Speter 267773Speter extern flagwas; 268773Speter /* 269773Speter * var := expr 270773Speter */ 271773Speter asgnop(r) 272773Speter int *r; 273773Speter { 274773Speter register struct nl *p; 275773Speter register *av; 276773Speter 277773Speter if (r == NIL) 278773Speter return (NIL); 279773Speter /* 280773Speter * Asgnop's only function is 281773Speter * to handle function variable 282773Speter * assignments. All other assignment 283773Speter * stuff is handled by asgnop1. 284773Speter * the if below checks for unqualified lefthandside: 285773Speter * necessary for fvars. 286773Speter */ 287773Speter av = r[2]; 288773Speter if (av != NIL && av[0] == T_VAR && av[3] == NIL) { 289773Speter p = lookup1(av[2]); 290773Speter if (p != NIL) 291773Speter p->nl_flags = flagwas; 292773Speter if (p != NIL && p->class == FVAR) { 293773Speter /* 294773Speter * Give asgnop1 the func 295773Speter * which is the chain of 296773Speter * the FVAR. 297773Speter */ 298773Speter p->nl_flags |= NUSED|NMOD; 299773Speter p = p->chain; 300773Speter if (p == NIL) { 301773Speter rvalue(r[3], NIL , RREQ ); 302773Speter return; 303773Speter } 304773Speter # ifdef OBJ 3053079Smckusic put(2, O_LV | bn << 8+INDX, (int)p->value[NL_OFFS]); 306773Speter if (isa(p->type, "i") && width(p->type) == 1) 307773Speter asgnop1(r, nl+T2INT); 308773Speter else 309773Speter asgnop1(r, p->type); 310773Speter # endif OBJ 311773Speter # ifdef PC 312773Speter /* 313773Speter * this should be the lvalue of the fvar, 314773Speter * but since the second pass knows to use 315773Speter * the address of the left operand of an 316773Speter * assignment, what i want here is an rvalue. 317773Speter * see note in funchdr about fvar allocation. 318773Speter */ 319773Speter p = p -> ptr[ NL_FVAR ]; 320773Speter putRV( p -> symbol , bn , p -> value[ NL_OFFS ] 321773Speter , p2type( p -> type ) ); 322773Speter asgnop1( r , p -> type ); 323773Speter # endif PC 324773Speter return; 325773Speter } 326773Speter } 327773Speter asgnop1(r, NIL); 328773Speter } 329773Speter 330773Speter /* 331773Speter * Asgnop1 handles all assignments. 332773Speter * If p is not nil then we are assigning 333773Speter * to a function variable, otherwise 334773Speter * we look the variable up ourselves. 335773Speter */ 336773Speter struct nl * 337773Speter asgnop1(r, p) 338773Speter int *r; 339773Speter register struct nl *p; 340773Speter { 341773Speter register struct nl *p1; 3423079Smckusic int w; 343773Speter 344773Speter if (r == NIL) 345773Speter return (NIL); 346773Speter if (p == NIL) { 347773Speter # ifdef OBJ 348773Speter p = lvalue(r[2], MOD|ASGN|NOUSE , LREQ ); 3493079Smckusic w = width(p); 350773Speter # endif OBJ 351773Speter # ifdef PC 352773Speter /* 353773Speter * since the second pass knows that it should reference 354773Speter * the lefthandside of asignments, what i need here is 355773Speter * an rvalue. 356773Speter */ 357773Speter p = lvalue( r[2] , MOD|ASGN|NOUSE , RREQ ); 358773Speter # endif PC 359773Speter if ( p == NIL ) { 360773Speter rvalue( r[3] , NIL , RREQ ); 361773Speter return NIL; 362773Speter } 363773Speter } 364773Speter # ifdef OBJ 3653079Smckusic /* 3663079Smckusic * assigning to the return value, which is at least 3673079Smckusic * of width two since it resides on the stack 3683079Smckusic */ 3693079Smckusic else { 3703079Smckusic w = width(p); 3713079Smckusic if (w < 2) 3723079Smckusic w = 2; 3733079Smckusic } 374773Speter p1 = rvalue(r[3], p , RREQ ); 375773Speter # endif OBJ 376773Speter # ifdef PC 377773Speter /* 378773Speter * if this is a scalar assignment, 379773Speter * then i want to rvalue the righthandside. 380773Speter * if this is a structure assignment, 381773Speter * then i want an lvalue to the righthandside. 382773Speter * that's what the intermediate form sez. 383773Speter */ 384773Speter switch ( classify( p ) ) { 385773Speter case TINT: 386773Speter case TCHAR: 387773Speter case TBOOL: 388773Speter case TSCAL: 389773Speter precheck( p , "_RANG4" , "_RSNG4" ); 390773Speter case TDOUBLE: 391773Speter case TPTR: 392773Speter p1 = rvalue( r[3] , p , RREQ ); 393773Speter break; 394773Speter default: 395773Speter p1 = rvalue( r[3] , p , LREQ ); 396773Speter break; 397773Speter } 398773Speter # endif PC 399773Speter if (p1 == NIL) 400773Speter return (NIL); 401773Speter if (incompat(p1, p, r[3])) { 402773Speter cerror("Type of expression clashed with type of variable in assignment"); 403773Speter return (NIL); 404773Speter } 405773Speter switch (classify(p)) { 406773Speter case TINT: 407773Speter case TBOOL: 408773Speter case TCHAR: 409773Speter case TSCAL: 410773Speter # ifdef OBJ 411773Speter rangechk(p, p1); 412773Speter # endif OBJ 413773Speter # ifdef PC 414773Speter postcheck( p ); 415773Speter # endif PC 416773Speter case TDOUBLE: 417773Speter case TPTR: 418773Speter # ifdef OBJ 4193079Smckusic gen(O_AS2, O_AS2, w, width(p1)); 420773Speter # endif OBJ 421773Speter # ifdef PC 422773Speter putop( P2ASSIGN , p2type( p ) ); 423773Speter putdot( filename , line ); 424773Speter # endif PC 425773Speter break; 426773Speter default: 427773Speter # ifdef OBJ 4283079Smckusic put(2, O_AS, w); 429773Speter # endif OBJ 430773Speter # ifdef PC 431773Speter putstrop( P2STASG , p2type( p ) 432773Speter , lwidth( p ) , align( p ) ); 433773Speter putdot( filename , line ); 434773Speter # endif PC 435773Speter } 436773Speter return (p); /* Used by for statement */ 437773Speter } 438773Speter 439773Speter /* 440773Speter * if expr then stat [ else stat ] 441773Speter */ 442773Speter ifop(r) 443773Speter int *r; 444773Speter { 445773Speter register struct nl *p; 446773Speter register l1, l2; /* l1 is start of else, l2 is end of else */ 4473079Smckusic int goc; 4483079Smckusic bool nr; 449773Speter 450773Speter goc = gocnt; 451773Speter if (r == NIL) 452773Speter return; 453773Speter putline(); 454773Speter p = rvalue(r[2], NIL , RREQ ); 455773Speter if (p == NIL) { 456773Speter statement(r[3]); 457773Speter noreach = 0; 458773Speter statement(r[4]); 459773Speter noreach = 0; 460773Speter return; 461773Speter } 462773Speter if (isnta(p, "b")) { 463773Speter error("Type of expression in if statement must be Boolean, not %s", nameof(p)); 464773Speter statement(r[3]); 465773Speter noreach = 0; 466773Speter statement(r[4]); 467773Speter noreach = 0; 468773Speter return; 469773Speter } 470773Speter # ifdef OBJ 4713079Smckusic l1 = put(2, O_IF, getlab()); 472773Speter # endif OBJ 473773Speter # ifdef PC 474773Speter l1 = getlab(); 475773Speter putleaf( P2ICON , l1 , 0 , P2INT , 0 ); 476773Speter putop( P2CBRANCH , P2INT ); 477773Speter putdot( filename , line ); 478773Speter # endif PC 479773Speter putcnt(); 480773Speter statement(r[3]); 481773Speter nr = noreach; 482773Speter if (r[4] != NIL) { 483773Speter /* 484773Speter * else stat 485773Speter */ 486773Speter --level; 487773Speter ungoto(); 488773Speter ++level; 489773Speter # ifdef OBJ 4903079Smckusic l2 = put(2, O_TRA, getlab()); 491773Speter # endif OBJ 492773Speter # ifdef PC 493773Speter l2 = getlab(); 494773Speter putjbr( l2 ); 495773Speter # endif PC 496773Speter patch(l1); 497773Speter noreach = 0; 498773Speter statement(r[4]); 4993079Smckusic noreach = (noreach && nr); 500773Speter l1 = l2; 501773Speter } else 502773Speter noreach = 0; 503773Speter patch(l1); 504773Speter if (goc != gocnt) 505773Speter putcnt(); 506773Speter } 507773Speter 508773Speter /* 509773Speter * while expr do stat 510773Speter */ 511773Speter whilop(r) 512773Speter int *r; 513773Speter { 514773Speter register struct nl *p; 515773Speter register l1, l2; 516773Speter int goc; 517773Speter 518773Speter goc = gocnt; 519773Speter if (r == NIL) 520773Speter return; 521773Speter putlab(l1 = getlab()); 522773Speter putline(); 523773Speter p = rvalue(r[2], NIL , RREQ ); 524773Speter if (p == NIL) { 525773Speter statement(r[3]); 526773Speter noreach = 0; 527773Speter return; 528773Speter } 529773Speter if (isnta(p, "b")) { 530773Speter error("Type of expression in while statement must be Boolean, not %s", nameof(p)); 531773Speter statement(r[3]); 532773Speter noreach = 0; 533773Speter return; 534773Speter } 535773Speter l2 = getlab(); 536773Speter # ifdef OBJ 5373079Smckusic put(2, O_IF, l2); 538773Speter # endif OBJ 539773Speter # ifdef PC 540773Speter putleaf( P2ICON , l2 , 0 , P2INT , 0 ); 541773Speter putop( P2CBRANCH , P2INT ); 542773Speter putdot( filename , line ); 543773Speter # endif PC 544773Speter putcnt(); 545773Speter statement(r[3]); 546773Speter # ifdef OBJ 5473079Smckusic put(2, O_TRA, l1); 548773Speter # endif OBJ 549773Speter # ifdef PC 550773Speter putjbr( l1 ); 551773Speter # endif PC 552773Speter patch(l2); 553773Speter if (goc != gocnt) 554773Speter putcnt(); 555773Speter } 556773Speter 557773Speter /* 558773Speter * repeat stat* until expr 559773Speter */ 560773Speter repop(r) 561773Speter int *r; 562773Speter { 563773Speter register struct nl *p; 564773Speter register l; 565773Speter int goc; 566773Speter 567773Speter goc = gocnt; 568773Speter if (r == NIL) 569773Speter return; 570773Speter l = putlab(getlab()); 571773Speter putcnt(); 572773Speter statlist(r[2]); 573773Speter line = r[1]; 574773Speter p = rvalue(r[3], NIL , RREQ ); 575773Speter if (p == NIL) 576773Speter return; 577773Speter if (isnta(p,"b")) { 578773Speter error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p)); 579773Speter return; 580773Speter } 581773Speter # ifdef OBJ 5823079Smckusic put(2, O_IF, l); 583773Speter # endif OBJ 584773Speter # ifdef PC 585773Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 586773Speter putop( P2CBRANCH , P2INT ); 587773Speter putdot( filename , line ); 588773Speter # endif PC 589773Speter if (goc != gocnt) 590773Speter putcnt(); 591773Speter } 592773Speter 593773Speter /* 594773Speter * assert expr 595773Speter */ 596773Speter asrtop(r) 597773Speter register int *r; 598773Speter { 599773Speter register struct nl *q; 600773Speter 601773Speter if (opt('s')) { 602773Speter standard(); 603773Speter error("Assert statement is non-standard"); 604773Speter } 605773Speter if (!opt('t')) 606773Speter return; 607773Speter r = r[2]; 608773Speter # ifdef OBJ 609773Speter q = rvalue((int *) r, NLNIL , RREQ ); 610773Speter # endif OBJ 611773Speter # ifdef PC 612773Speter putleaf( P2ICON , 0 , 0 613773Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ASRT" ); 614773Speter q = stkrval( r , NLNIL , RREQ ); 615773Speter # endif PC 616773Speter if (q == NIL) 617773Speter return; 618773Speter if (isnta(q, "b")) 619773Speter error("Assert expression must be Boolean, not %ss", nameof(q)); 620773Speter # ifdef OBJ 6213079Smckusic put(1, O_ASRT); 622773Speter # endif OBJ 623773Speter # ifdef PC 624773Speter putop( P2CALL , P2INT ); 625773Speter putdot( filename , line ); 626773Speter # endif PC 627773Speter } 628