1773Speter /* Copyright (c) 1979 Regents of the University of California */ 2773Speter 3*11854Speter static char sccsid[] = "@(#)stat.c 1.11 04/06/83"; 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 1311330Speter #include "tmps.h" 14773Speter 15773Speter int cntstat; 16773Speter short cnts = 3; 17773Speter #include "opcode.h" 18773Speter 19773Speter /* 20773Speter * Statement list 21773Speter */ 22773Speter statlist(r) 23773Speter int *r; 24773Speter { 25773Speter register *sl; 26773Speter 27773Speter for (sl=r; sl != NIL; sl=sl[2]) 28773Speter statement(sl[1]); 29773Speter } 30773Speter 31773Speter /* 32773Speter * Statement 33773Speter */ 34773Speter statement(r) 35773Speter int *r; 36773Speter { 37773Speter register *s; 38773Speter register struct nl *snlp; 393228Smckusic struct tmps soffset; 40773Speter 41773Speter s = r; 42773Speter snlp = nlp; 433228Smckusic soffset = sizes[cbn].curtmps; 44773Speter top: 45773Speter if (cntstat) { 46773Speter cntstat = 0; 47773Speter putcnt(); 48773Speter } 49773Speter if (s == NIL) 50773Speter return; 51773Speter line = s[1]; 52773Speter if (s[0] == T_LABEL) { 53773Speter labeled(s[2]); 54773Speter s = s[3]; 55773Speter noreach = 0; 56773Speter cntstat = 1; 57773Speter goto top; 58773Speter } 59773Speter if (noreach) { 60773Speter noreach = 0; 61773Speter warning(); 62773Speter error("Unreachable statement"); 63773Speter } 64773Speter switch (s[0]) { 65773Speter case T_PCALL: 66773Speter putline(); 67773Speter # ifdef OBJ 68773Speter proc(s); 69773Speter # endif OBJ 70773Speter # ifdef PC 71773Speter pcproc( s ); 72773Speter # endif PC 73773Speter break; 74773Speter case T_ASGN: 75773Speter putline(); 76773Speter asgnop(s); 77773Speter break; 78773Speter case T_GOTO: 79773Speter putline(); 80773Speter gotoop(s[2]); 81773Speter noreach = 1; 82773Speter cntstat = 1; 83773Speter break; 84773Speter default: 85773Speter level++; 86773Speter switch (s[0]) { 87773Speter default: 88773Speter panic("stat"); 89773Speter case T_IF: 90773Speter case T_IFEL: 91773Speter ifop(s); 92773Speter break; 93773Speter case T_WHILE: 94773Speter whilop(s); 95773Speter noreach = 0; 96773Speter break; 97773Speter case T_REPEAT: 98773Speter repop(s); 99773Speter break; 100773Speter case T_FORU: 101773Speter case T_FORD: 1022185Smckusic forop(s); 103773Speter noreach = 0; 104773Speter break; 105773Speter case T_BLOCK: 106773Speter statlist(s[2]); 107773Speter break; 108773Speter case T_CASE: 109773Speter putline(); 110773Speter # ifdef OBJ 111773Speter caseop(s); 112773Speter # endif OBJ 113773Speter # ifdef PC 114773Speter pccaseop( s ); 115773Speter # endif PC 116773Speter break; 117773Speter case T_WITH: 118773Speter withop(s); 119773Speter break; 120773Speter } 121773Speter --level; 122773Speter if (gotos[cbn]) 123773Speter ungoto(); 124773Speter break; 125773Speter } 126773Speter /* 127773Speter * Free the temporary name list entries defined in 128773Speter * expressions, e.g. STRs, and WITHPTRs from withs. 129773Speter */ 130773Speter nlfree(snlp); 131773Speter /* 132773Speter * free any temporaries allocated for this statement 133773Speter * these come from strings and sets. 134773Speter */ 1353228Smckusic tmpfree(&soffset); 136773Speter } 137773Speter 138773Speter ungoto() 139773Speter { 140773Speter register struct nl *p; 141773Speter 142773Speter for (p = gotos[cbn]; p != NIL; p = p->chain) 143773Speter if ((p->nl_flags & NFORWD) != 0) { 144773Speter if (p->value[NL_GOLEV] != NOTYET) 145773Speter if (p->value[NL_GOLEV] > level) 146773Speter p->value[NL_GOLEV] = level; 147773Speter } else 148773Speter if (p->value[NL_GOLEV] != DEAD) 149773Speter if (p->value[NL_GOLEV] > level) 150773Speter p->value[NL_GOLEV] = DEAD; 151773Speter } 152773Speter 153773Speter putcnt() 154773Speter { 155773Speter 156773Speter if (monflg == 0) { 157773Speter return; 158773Speter } 159773Speter inccnt( getcnt() ); 160773Speter } 161773Speter 162773Speter int 163773Speter getcnt() 164773Speter { 165773Speter 166773Speter return ++cnts; 167773Speter } 168773Speter 169773Speter inccnt( counter ) 170773Speter int counter; 171773Speter { 172773Speter 173773Speter # ifdef OBJ 1743079Smckusic put(2, O_COUNT, counter ); 175773Speter # endif OBJ 176773Speter # ifdef PC 1773835Speter putRV( PCPCOUNT , 0 , counter * sizeof (long) , NGLOBAL , P2INT ); 178773Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 179773Speter putop( P2ASG P2PLUS , P2INT ); 180773Speter putdot( filename , line ); 181773Speter # endif PC 182773Speter } 183773Speter 184773Speter putline() 185773Speter { 186773Speter 187773Speter # ifdef OBJ 188773Speter if (opt('p') != 0) 1893079Smckusic put(2, O_LINO, line); 1905654Slinton 1915654Slinton /* 1925654Slinton * put out line number information for pdx 1935654Slinton */ 1945654Slinton lineno(line); 1955654Slinton 196773Speter # endif OBJ 197773Speter # ifdef PC 198773Speter static lastline; 199773Speter 200773Speter if ( line != lastline ) { 201773Speter stabline( line ); 202773Speter lastline = line; 203773Speter } 204773Speter if ( opt( 'p' ) ) { 205773Speter if ( opt('t') ) { 206773Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 207773Speter , "_LINO" ); 208773Speter putop( P2UNARY P2CALL , P2INT ); 209773Speter putdot( filename , line ); 210773Speter } else { 2113835Speter putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 212773Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 213773Speter putop( P2ASG P2PLUS , P2INT ); 214773Speter putdot( filename , line ); 215773Speter } 216773Speter } 217773Speter # endif PC 218773Speter } 219773Speter 220773Speter /* 221773Speter * With varlist do stat 222773Speter * 223773Speter * With statement requires an extra word 224773Speter * in automatic storage for each level of withing. 225773Speter * These indirect pointers are initialized here, and 226773Speter * the scoping effect of the with statement occurs 227773Speter * because lookup examines the field names of the records 228773Speter * associated with the WITHPTRs on the withlist. 229773Speter */ 230773Speter withop(s) 231773Speter int *s; 232773Speter { 233773Speter register *p; 234773Speter register struct nl *r; 2353835Speter struct nl *tempnlp; 236773Speter int *swl; 237773Speter 238773Speter putline(); 239773Speter swl = withlist; 240773Speter for (p = s[2]; p != NIL; p = p[2]) { 2413835Speter tempnlp = tmpalloc(sizeof(int *), INT_TYP, REGOK); 242773Speter # ifdef OBJ 2433835Speter put(2, O_LV | cbn <<8+INDX, tempnlp -> value[ NL_OFFS ] ); 244773Speter # endif OBJ 245773Speter # ifdef PC 2463835Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 2473835Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 248773Speter # endif PC 249773Speter r = lvalue(p[1], MOD , LREQ ); 250773Speter if (r == NIL) 251773Speter continue; 252773Speter if (r->class != RECORD) { 253773Speter error("Variable in with statement refers to %s, not to a record", nameof(r)); 254773Speter continue; 255773Speter } 2563835Speter r = defnl(0, WITHPTR, r, tempnlp -> value[ NL_OFFS ] ); 2573835Speter # ifdef PC 2583835Speter r -> extra_flags |= tempnlp -> extra_flags; 2593835Speter # endif PC 260773Speter r->nl_next = withlist; 261773Speter withlist = r; 262773Speter # ifdef OBJ 263773Speter put(1, PTR_AS); 264773Speter # endif OBJ 265773Speter # ifdef PC 266773Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 267773Speter putdot( filename , line ); 268773Speter # endif PC 269773Speter } 270773Speter statement(s[3]); 271773Speter withlist = swl; 272773Speter } 273773Speter 274773Speter extern flagwas; 275773Speter /* 276773Speter * var := expr 277773Speter */ 278773Speter asgnop(r) 279773Speter int *r; 280773Speter { 281773Speter register struct nl *p; 282773Speter register *av; 283773Speter 284773Speter if (r == NIL) 285773Speter return (NIL); 286773Speter /* 287773Speter * Asgnop's only function is 288773Speter * to handle function variable 289773Speter * assignments. All other assignment 290773Speter * stuff is handled by asgnop1. 291773Speter * the if below checks for unqualified lefthandside: 292773Speter * necessary for fvars. 293773Speter */ 294773Speter av = r[2]; 295773Speter if (av != NIL && av[0] == T_VAR && av[3] == NIL) { 296773Speter p = lookup1(av[2]); 297773Speter if (p != NIL) 298773Speter p->nl_flags = flagwas; 299773Speter if (p != NIL && p->class == FVAR) { 300773Speter /* 301773Speter * Give asgnop1 the func 302773Speter * which is the chain of 303773Speter * the FVAR. 304773Speter */ 305773Speter p->nl_flags |= NUSED|NMOD; 306773Speter p = p->chain; 307773Speter if (p == NIL) { 308773Speter rvalue(r[3], NIL , RREQ ); 309773Speter return; 310773Speter } 311773Speter # ifdef OBJ 3123079Smckusic put(2, O_LV | bn << 8+INDX, (int)p->value[NL_OFFS]); 313773Speter if (isa(p->type, "i") && width(p->type) == 1) 314773Speter asgnop1(r, nl+T2INT); 315773Speter else 316773Speter asgnop1(r, p->type); 317773Speter # endif OBJ 318773Speter # ifdef PC 319773Speter /* 320773Speter * this should be the lvalue of the fvar, 321773Speter * but since the second pass knows to use 322773Speter * the address of the left operand of an 323773Speter * assignment, what i want here is an rvalue. 324773Speter * see note in funchdr about fvar allocation. 325773Speter */ 326773Speter p = p -> ptr[ NL_FVAR ]; 3273835Speter putRV( p -> symbol , bn , p -> value[ NL_OFFS ] , 3283835Speter p -> extra_flags , p2type( p -> type ) ); 329773Speter asgnop1( r , p -> type ); 330773Speter # endif PC 331773Speter return; 332773Speter } 333773Speter } 334773Speter asgnop1(r, NIL); 335773Speter } 336773Speter 337773Speter /* 338773Speter * Asgnop1 handles all assignments. 339773Speter * If p is not nil then we are assigning 340773Speter * to a function variable, otherwise 341773Speter * we look the variable up ourselves. 342773Speter */ 343773Speter struct nl * 344773Speter asgnop1(r, p) 345773Speter int *r; 346773Speter register struct nl *p; 347773Speter { 348773Speter register struct nl *p1; 3493079Smckusic int w; 350773Speter 351773Speter if (r == NIL) 352773Speter return (NIL); 353773Speter if (p == NIL) { 354773Speter # ifdef OBJ 355773Speter p = lvalue(r[2], MOD|ASGN|NOUSE , LREQ ); 3563079Smckusic w = width(p); 357773Speter # endif OBJ 358773Speter # ifdef PC 359773Speter /* 360773Speter * since the second pass knows that it should reference 361773Speter * the lefthandside of asignments, what i need here is 362773Speter * an rvalue. 363773Speter */ 364773Speter p = lvalue( r[2] , MOD|ASGN|NOUSE , RREQ ); 365773Speter # endif PC 366773Speter if ( p == NIL ) { 367773Speter rvalue( r[3] , NIL , RREQ ); 368773Speter return NIL; 369773Speter } 370773Speter } 371773Speter # ifdef OBJ 3723079Smckusic /* 3733079Smckusic * assigning to the return value, which is at least 3743079Smckusic * of width two since it resides on the stack 3753079Smckusic */ 3763079Smckusic else { 3773079Smckusic w = width(p); 3783079Smckusic if (w < 2) 3793079Smckusic w = 2; 3803079Smckusic } 381773Speter p1 = rvalue(r[3], p , RREQ ); 382773Speter # endif OBJ 383773Speter # ifdef PC 384773Speter /* 385773Speter * if this is a scalar assignment, 386773Speter * then i want to rvalue the righthandside. 387773Speter * if this is a structure assignment, 388773Speter * then i want an lvalue to the righthandside. 389773Speter * that's what the intermediate form sez. 390773Speter */ 391773Speter switch ( classify( p ) ) { 392773Speter case TINT: 393773Speter case TCHAR: 394773Speter case TBOOL: 395773Speter case TSCAL: 396773Speter precheck( p , "_RANG4" , "_RSNG4" ); 397773Speter case TDOUBLE: 398773Speter case TPTR: 399773Speter p1 = rvalue( r[3] , p , RREQ ); 400773Speter break; 401773Speter default: 402773Speter p1 = rvalue( r[3] , p , LREQ ); 403773Speter break; 404773Speter } 405773Speter # endif PC 406773Speter if (p1 == NIL) 407773Speter return (NIL); 408773Speter if (incompat(p1, p, r[3])) { 409773Speter cerror("Type of expression clashed with type of variable in assignment"); 410773Speter return (NIL); 411773Speter } 4128758Speter # ifdef OBJ 4138758Speter switch (classify(p)) { 4148758Speter case TINT: 4158758Speter case TBOOL: 4168758Speter case TCHAR: 4178758Speter case TSCAL: 418773Speter rangechk(p, p1); 4198758Speter gen(O_AS2, O_AS2, w, width(p1)); 4208758Speter break; 4218758Speter case TDOUBLE: 4228758Speter case TPTR: 4238758Speter gen(O_AS2, O_AS2, w, width(p1)); 4248758Speter break; 4258758Speter default: 4268758Speter put(2, O_AS, w); 4278758Speter break; 4288758Speter } 4298758Speter # endif OBJ 4308758Speter # ifdef PC 4318758Speter switch (classify(p)) { 4328758Speter case TINT: 4338758Speter case TBOOL: 4348758Speter case TCHAR: 4358758Speter case TSCAL: 43610362Smckusick postcheck(p, p1); 43710362Smckusick sconv(p2type(p1), p2type(p)); 438773Speter putop( P2ASSIGN , p2type( p ) ); 439773Speter putdot( filename , line ); 4408758Speter break; 4418758Speter case TPTR: 4428758Speter putop( P2ASSIGN , p2type( p ) ); 4438758Speter putdot( filename , line ); 4448758Speter break; 4458758Speter case TDOUBLE: 44610362Smckusick sconv(p2type(p1), p2type(p)); 4478758Speter putop( P2ASSIGN , p2type( p ) ); 4488758Speter putdot( filename , line ); 4498758Speter break; 4508758Speter default: 451*11854Speter putstrop(P2STASG, ADDTYPE(p2type(p), P2PTR), 452*11854Speter lwidth(p), align(p)); 453773Speter putdot( filename , line ); 4548758Speter break; 4558758Speter } 4568758Speter # endif PC 457773Speter return (p); /* Used by for statement */ 458773Speter } 459773Speter 460773Speter /* 461773Speter * if expr then stat [ else stat ] 462773Speter */ 463773Speter ifop(r) 464773Speter int *r; 465773Speter { 466773Speter register struct nl *p; 467773Speter register l1, l2; /* l1 is start of else, l2 is end of else */ 4683079Smckusic int goc; 4693079Smckusic bool nr; 470773Speter 471773Speter goc = gocnt; 472773Speter if (r == NIL) 473773Speter return; 474773Speter putline(); 475773Speter p = rvalue(r[2], NIL , RREQ ); 476773Speter if (p == NIL) { 477773Speter statement(r[3]); 478773Speter noreach = 0; 479773Speter statement(r[4]); 480773Speter noreach = 0; 481773Speter return; 482773Speter } 483773Speter if (isnta(p, "b")) { 484773Speter error("Type of expression in if statement must be Boolean, not %s", nameof(p)); 485773Speter statement(r[3]); 486773Speter noreach = 0; 487773Speter statement(r[4]); 488773Speter noreach = 0; 489773Speter return; 490773Speter } 491773Speter # ifdef OBJ 4923079Smckusic l1 = put(2, O_IF, getlab()); 493773Speter # endif OBJ 494773Speter # ifdef PC 495773Speter l1 = getlab(); 496773Speter putleaf( P2ICON , l1 , 0 , P2INT , 0 ); 497773Speter putop( P2CBRANCH , P2INT ); 498773Speter putdot( filename , line ); 499773Speter # endif PC 500773Speter putcnt(); 501773Speter statement(r[3]); 502773Speter nr = noreach; 503773Speter if (r[4] != NIL) { 504773Speter /* 505773Speter * else stat 506773Speter */ 507773Speter --level; 508773Speter ungoto(); 509773Speter ++level; 510773Speter # ifdef OBJ 5113079Smckusic l2 = put(2, O_TRA, getlab()); 512773Speter # endif OBJ 513773Speter # ifdef PC 514773Speter l2 = getlab(); 515773Speter putjbr( l2 ); 516773Speter # endif PC 517773Speter patch(l1); 518773Speter noreach = 0; 519773Speter statement(r[4]); 5203079Smckusic noreach = (noreach && nr); 521773Speter l1 = l2; 522773Speter } else 523773Speter noreach = 0; 524773Speter patch(l1); 525773Speter if (goc != gocnt) 526773Speter putcnt(); 527773Speter } 528773Speter 529773Speter /* 530773Speter * while expr do stat 531773Speter */ 532773Speter whilop(r) 533773Speter int *r; 534773Speter { 535773Speter register struct nl *p; 536773Speter register l1, l2; 537773Speter int goc; 538773Speter 539773Speter goc = gocnt; 540773Speter if (r == NIL) 541773Speter return; 542773Speter putlab(l1 = getlab()); 543773Speter putline(); 544773Speter p = rvalue(r[2], NIL , RREQ ); 545773Speter if (p == NIL) { 546773Speter statement(r[3]); 547773Speter noreach = 0; 548773Speter return; 549773Speter } 550773Speter if (isnta(p, "b")) { 551773Speter error("Type of expression in while statement must be Boolean, not %s", nameof(p)); 552773Speter statement(r[3]); 553773Speter noreach = 0; 554773Speter return; 555773Speter } 556773Speter l2 = getlab(); 557773Speter # ifdef OBJ 5583079Smckusic put(2, O_IF, l2); 559773Speter # endif OBJ 560773Speter # ifdef PC 561773Speter putleaf( P2ICON , l2 , 0 , P2INT , 0 ); 562773Speter putop( P2CBRANCH , P2INT ); 563773Speter putdot( filename , line ); 564773Speter # endif PC 565773Speter putcnt(); 566773Speter statement(r[3]); 567773Speter # ifdef OBJ 5683079Smckusic put(2, O_TRA, l1); 569773Speter # endif OBJ 570773Speter # ifdef PC 571773Speter putjbr( l1 ); 572773Speter # endif PC 573773Speter patch(l2); 574773Speter if (goc != gocnt) 575773Speter putcnt(); 576773Speter } 577773Speter 578773Speter /* 579773Speter * repeat stat* until expr 580773Speter */ 581773Speter repop(r) 582773Speter int *r; 583773Speter { 584773Speter register struct nl *p; 585773Speter register l; 586773Speter int goc; 587773Speter 588773Speter goc = gocnt; 589773Speter if (r == NIL) 590773Speter return; 591773Speter l = putlab(getlab()); 592773Speter putcnt(); 593773Speter statlist(r[2]); 594773Speter line = r[1]; 595773Speter p = rvalue(r[3], NIL , RREQ ); 596773Speter if (p == NIL) 597773Speter return; 598773Speter if (isnta(p,"b")) { 599773Speter error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p)); 600773Speter return; 601773Speter } 602773Speter # ifdef OBJ 6033079Smckusic put(2, O_IF, l); 604773Speter # endif OBJ 605773Speter # ifdef PC 606773Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 607773Speter putop( P2CBRANCH , P2INT ); 608773Speter putdot( filename , line ); 609773Speter # endif PC 610773Speter if (goc != gocnt) 611773Speter putcnt(); 612773Speter } 613