1773Speter /* Copyright (c) 1979 Regents of the University of California */ 2773Speter 3*15941Smckusick #ifndef lint 4*15941Smckusick static char sccsid[] = "@(#)stat.c 1.11.1.1 02/04/84"; 5*15941Smckusick #endif 6773Speter 7773Speter #include "whoami.h" 8773Speter #include "0.h" 9773Speter #include "tree.h" 10773Speter #include "objfmt.h" 11773Speter #ifdef PC 12773Speter # include "pcops.h" 13773Speter # include "pc.h" 14773Speter #endif PC 1511330Speter #include "tmps.h" 16773Speter 17773Speter int cntstat; 18773Speter short cnts = 3; 19773Speter #include "opcode.h" 20*15941Smckusick #include "tree_ty.h" 21773Speter 22773Speter /* 23773Speter * Statement list 24773Speter */ 25773Speter statlist(r) 26*15941Smckusick struct tnode *r; 27773Speter { 28*15941Smckusick register struct tnode *sl; 29773Speter 30*15941Smckusick for (sl=r; sl != TR_NIL; sl=sl->list_node.next) 31*15941Smckusick statement(sl->list_node.list); 32773Speter } 33773Speter 34773Speter /* 35773Speter * Statement 36773Speter */ 37773Speter statement(r) 38*15941Smckusick struct tnode *r; 39773Speter { 40*15941Smckusick register struct tnode *tree_node; 41773Speter register struct nl *snlp; 423228Smckusic struct tmps soffset; 43773Speter 44*15941Smckusick tree_node = r; 45773Speter snlp = nlp; 463228Smckusic soffset = sizes[cbn].curtmps; 47773Speter top: 48773Speter if (cntstat) { 49773Speter cntstat = 0; 50773Speter putcnt(); 51773Speter } 52*15941Smckusick if (tree_node == TR_NIL) 53773Speter return; 54*15941Smckusick line = tree_node->lined.line_no; 55*15941Smckusick if (tree_node->tag == T_LABEL) { 56*15941Smckusick labeled(tree_node->label_node.lbl_ptr); 57*15941Smckusick tree_node = tree_node->label_node.stmnt; 58*15941Smckusick noreach = FALSE; 59773Speter cntstat = 1; 60773Speter goto top; 61773Speter } 62773Speter if (noreach) { 63*15941Smckusick noreach = FALSE; 64773Speter warning(); 65773Speter error("Unreachable statement"); 66773Speter } 67*15941Smckusick switch (tree_node->tag) { 68773Speter case T_PCALL: 69773Speter putline(); 70773Speter # ifdef OBJ 71*15941Smckusick proc(tree_node); 72773Speter # endif OBJ 73773Speter # ifdef PC 74*15941Smckusick pcproc( tree_node ); 75773Speter # endif PC 76773Speter break; 77773Speter case T_ASGN: 78773Speter putline(); 79*15941Smckusick asgnop(&(tree_node->asg_node)); 80773Speter break; 81773Speter case T_GOTO: 82773Speter putline(); 83*15941Smckusick gotoop(tree_node->goto_node.lbl_ptr); 84*15941Smckusick noreach = TRUE; 85773Speter cntstat = 1; 86773Speter break; 87773Speter default: 88773Speter level++; 89*15941Smckusick switch (tree_node->tag) { 90773Speter default: 91773Speter panic("stat"); 92773Speter case T_IF: 93773Speter case T_IFEL: 94*15941Smckusick ifop(&(tree_node->if_node)); 95773Speter break; 96773Speter case T_WHILE: 97*15941Smckusick whilop(&(tree_node->whi_cas)); 98*15941Smckusick noreach = FALSE; 99773Speter break; 100773Speter case T_REPEAT: 101*15941Smckusick repop(&(tree_node->repeat)); 102773Speter break; 103773Speter case T_FORU: 104773Speter case T_FORD: 105*15941Smckusick forop(tree_node); 106*15941Smckusick noreach = FALSE; 107773Speter break; 108773Speter case T_BLOCK: 109*15941Smckusick statlist(tree_node->stmnt_blck.stmnt_list); 110773Speter break; 111773Speter case T_CASE: 112773Speter putline(); 113773Speter # ifdef OBJ 114*15941Smckusick caseop(&(tree_node->whi_cas)); 115773Speter # endif OBJ 116773Speter # ifdef PC 117*15941Smckusick pccaseop(&(tree_node->whi_cas)); 118773Speter # endif PC 119773Speter break; 120773Speter case T_WITH: 121*15941Smckusick withop(&(tree_node->with_node)); 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 */ 1383228Smckusic tmpfree(&soffset); 139773Speter } 140773Speter 141773Speter ungoto() 142773Speter { 143773Speter register struct nl *p; 144773Speter 145*15941Smckusick for (p = gotos[cbn]; p != NLNIL; 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 159*15941Smckusick if (monflg == FALSE) { 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 177*15941Smckusick (void) put(2, O_COUNT, counter ); 178773Speter # endif OBJ 179773Speter # ifdef PC 1803835Speter putRV( PCPCOUNT , 0 , counter * sizeof (long) , NGLOBAL , P2INT ); 181*15941Smckusick putleaf( P2ICON , 1 , 0 , P2INT , (char *) 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) 192*15941Smckusick (void) put(2, O_LINO, line); 1935654Slinton 1945654Slinton /* 1955654Slinton * put out line number information for pdx 1965654Slinton */ 1975654Slinton lineno(line); 1985654Slinton 199773Speter # endif OBJ 200773Speter # ifdef PC 201773Speter static lastline; 202773Speter 203773Speter if ( line != lastline ) { 204773Speter stabline( line ); 205773Speter lastline = line; 206773Speter } 207773Speter if ( opt( 'p' ) ) { 208773Speter if ( opt('t') ) { 209773Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 210773Speter , "_LINO" ); 211773Speter putop( P2UNARY P2CALL , P2INT ); 212773Speter putdot( filename , line ); 213773Speter } else { 2143835Speter putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 215*15941Smckusick putleaf( P2ICON , 1 , 0 , P2INT , (char *) 0 ); 216773Speter putop( P2ASG P2PLUS , P2INT ); 217773Speter putdot( filename , line ); 218773Speter } 219773Speter } 220773Speter # endif PC 221773Speter } 222773Speter 223773Speter /* 224773Speter * With varlist do stat 225773Speter * 226773Speter * With statement requires an extra word 227773Speter * in automatic storage for each level of withing. 228773Speter * These indirect pointers are initialized here, and 229773Speter * the scoping effect of the with statement occurs 230773Speter * because lookup examines the field names of the records 231773Speter * associated with the WITHPTRs on the withlist. 232773Speter */ 233773Speter withop(s) 234*15941Smckusick WITH_NODE *s; 235773Speter { 236*15941Smckusick register struct tnode *p; 237773Speter register struct nl *r; 2383835Speter struct nl *tempnlp; 239*15941Smckusick struct nl *swl; 240773Speter 241773Speter putline(); 242773Speter swl = withlist; 243*15941Smckusick for (p = s->var_list; p != TR_NIL; p = p->list_node.next) { 244*15941Smckusick tempnlp = tmpalloc((long) (sizeof(int *)), INT_TYP, REGOK); 245773Speter # ifdef OBJ 246*15941Smckusick (void) put(2, O_LV | cbn <<8+INDX, tempnlp -> value[ NL_OFFS ] ); 247773Speter # endif OBJ 248773Speter # ifdef PC 249*15941Smckusick putRV( (char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] , 2503835Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 251773Speter # endif PC 252*15941Smckusick r = lvalue(p->list_node.list, MOD , LREQ ); 253*15941Smckusick if (r == NLNIL) 254773Speter continue; 255773Speter if (r->class != RECORD) { 256773Speter error("Variable in with statement refers to %s, not to a record", nameof(r)); 257773Speter continue; 258773Speter } 259*15941Smckusick r = defnl((char *) 0, WITHPTR, r, tempnlp -> value[ NL_OFFS ] ); 2603835Speter # ifdef PC 2613835Speter r -> extra_flags |= tempnlp -> extra_flags; 2623835Speter # endif PC 263773Speter r->nl_next = withlist; 264773Speter withlist = r; 265773Speter # ifdef OBJ 266*15941Smckusick (void) put(1, PTR_AS); 267773Speter # endif OBJ 268773Speter # ifdef PC 269773Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 270773Speter putdot( filename , line ); 271773Speter # endif PC 272773Speter } 273*15941Smckusick statement(s->stmnt); 274773Speter withlist = swl; 275773Speter } 276773Speter 277773Speter extern flagwas; 278773Speter /* 279773Speter * var := expr 280773Speter */ 281773Speter asgnop(r) 282*15941Smckusick ASG_NODE *r; 283773Speter { 284773Speter register struct nl *p; 285*15941Smckusick register struct tnode *av; 286773Speter 287773Speter /* 288773Speter * Asgnop's only function is 289773Speter * to handle function variable 290773Speter * assignments. All other assignment 291773Speter * stuff is handled by asgnop1. 292773Speter * the if below checks for unqualified lefthandside: 293773Speter * necessary for fvars. 294773Speter */ 295*15941Smckusick av = r->lhs_var; 296*15941Smckusick if (av != TR_NIL && av->tag == T_VAR && av->var_node.qual == TR_NIL) { 297*15941Smckusick p = lookup1(av->var_node.cptr); 298*15941Smckusick if (p != NLNIL) 299773Speter p->nl_flags = flagwas; 300*15941Smckusick if (p != NLNIL && p->class == FVAR) { 301773Speter /* 302773Speter * Give asgnop1 the func 303773Speter * which is the chain of 304773Speter * the FVAR. 305773Speter */ 306773Speter p->nl_flags |= NUSED|NMOD; 307773Speter p = p->chain; 308*15941Smckusick if (p == NLNIL) { 309*15941Smckusick p = rvalue(r->rhs_expr, NLNIL , RREQ ); 310773Speter return; 311773Speter } 312773Speter # ifdef OBJ 313*15941Smckusick (void) put(2, O_LV | bn << 8+INDX, (int)p->value[NL_OFFS]); 314773Speter if (isa(p->type, "i") && width(p->type) == 1) 315*15941Smckusick (void) asgnop1(r, nl+T2INT); 316773Speter else 317*15941Smckusick (void) asgnop1(r, p->type); 318773Speter # endif OBJ 319773Speter # ifdef PC 320773Speter /* 321773Speter * this should be the lvalue of the fvar, 322773Speter * but since the second pass knows to use 323773Speter * the address of the left operand of an 324773Speter * assignment, what i want here is an rvalue. 325773Speter * see note in funchdr about fvar allocation. 326773Speter */ 327773Speter p = p -> ptr[ NL_FVAR ]; 3283835Speter putRV( p -> symbol , bn , p -> value[ NL_OFFS ] , 3293835Speter p -> extra_flags , p2type( p -> type ) ); 330*15941Smckusick (void) asgnop1( r , p -> type ); 331773Speter # endif PC 332773Speter return; 333773Speter } 334773Speter } 335*15941Smckusick (void) asgnop1(r, NLNIL); 336773Speter } 337773Speter 338773Speter /* 339773Speter * Asgnop1 handles all assignments. 340773Speter * If p is not nil then we are assigning 341773Speter * to a function variable, otherwise 342773Speter * we look the variable up ourselves. 343773Speter */ 344773Speter struct nl * 345773Speter asgnop1(r, p) 346*15941Smckusick ASG_NODE *r; 347773Speter register struct nl *p; 348773Speter { 349773Speter register struct nl *p1; 350*15941Smckusick #ifdef OBJ 3513079Smckusic int w; 352*15941Smckusick #endif 353773Speter 354*15941Smckusick if (p == NLNIL) { 355773Speter # ifdef OBJ 356*15941Smckusick p = lvalue(r->lhs_var, MOD|ASGN|NOUSE , LREQ ); 3573079Smckusic w = width(p); 358773Speter # endif OBJ 359773Speter # ifdef PC 360773Speter /* 361773Speter * since the second pass knows that it should reference 362773Speter * the lefthandside of asignments, what i need here is 363773Speter * an rvalue. 364773Speter */ 365*15941Smckusick p = lvalue( r->lhs_var , MOD|ASGN|NOUSE , RREQ ); 366773Speter # endif PC 367*15941Smckusick if ( p == NLNIL ) { 368*15941Smckusick (void) rvalue( r->rhs_expr , NLNIL , RREQ ); 369*15941Smckusick return NLNIL; 370773Speter } 371773Speter } 372773Speter # ifdef OBJ 3733079Smckusic /* 3743079Smckusic * assigning to the return value, which is at least 3753079Smckusic * of width two since it resides on the stack 3763079Smckusic */ 3773079Smckusic else { 3783079Smckusic w = width(p); 3793079Smckusic if (w < 2) 3803079Smckusic w = 2; 3813079Smckusic } 382*15941Smckusick p1 = rvalue(r->rhs_expr, p , RREQ ); 383773Speter # endif OBJ 384773Speter # ifdef PC 385773Speter /* 386773Speter * if this is a scalar assignment, 387773Speter * then i want to rvalue the righthandside. 388773Speter * if this is a structure assignment, 389773Speter * then i want an lvalue to the righthandside. 390773Speter * that's what the intermediate form sez. 391773Speter */ 392773Speter switch ( classify( p ) ) { 393773Speter case TINT: 394773Speter case TCHAR: 395773Speter case TBOOL: 396773Speter case TSCAL: 397773Speter precheck( p , "_RANG4" , "_RSNG4" ); 398773Speter case TDOUBLE: 399773Speter case TPTR: 400*15941Smckusick p1 = rvalue( r->rhs_expr , p , RREQ ); 401773Speter break; 402773Speter default: 403*15941Smckusick p1 = rvalue( r->rhs_expr , p , LREQ ); 404773Speter break; 405773Speter } 406773Speter # endif PC 407*15941Smckusick if (p1 == NLNIL) 408*15941Smckusick return (NLNIL); 409*15941Smckusick if (incompat(p1, p, r->rhs_expr)) { 410773Speter cerror("Type of expression clashed with type of variable in assignment"); 411*15941Smckusick return (NLNIL); 412773Speter } 4138758Speter # ifdef OBJ 4148758Speter switch (classify(p)) { 4158758Speter case TINT: 4168758Speter case TBOOL: 4178758Speter case TCHAR: 4188758Speter case TSCAL: 419773Speter rangechk(p, p1); 420*15941Smckusick (void) gen(O_AS2, O_AS2, w, width(p1)); 4218758Speter break; 4228758Speter case TDOUBLE: 4238758Speter case TPTR: 424*15941Smckusick (void) gen(O_AS2, O_AS2, w, width(p1)); 4258758Speter break; 4268758Speter default: 427*15941Smckusick (void) put(2, O_AS, w); 4288758Speter break; 4298758Speter } 4308758Speter # endif OBJ 4318758Speter # ifdef PC 4328758Speter switch (classify(p)) { 4338758Speter case TINT: 4348758Speter case TBOOL: 4358758Speter case TCHAR: 4368758Speter case TSCAL: 43710362Smckusick postcheck(p, p1); 43810362Smckusick sconv(p2type(p1), p2type(p)); 439773Speter putop( P2ASSIGN , p2type( p ) ); 440773Speter putdot( filename , line ); 4418758Speter break; 4428758Speter case TPTR: 4438758Speter putop( P2ASSIGN , p2type( p ) ); 4448758Speter putdot( filename , line ); 4458758Speter break; 4468758Speter case TDOUBLE: 44710362Smckusick sconv(p2type(p1), p2type(p)); 4488758Speter putop( P2ASSIGN , p2type( p ) ); 4498758Speter putdot( filename , line ); 4508758Speter break; 4518758Speter default: 45211854Speter putstrop(P2STASG, ADDTYPE(p2type(p), P2PTR), 453*15941Smckusick (int) lwidth(p), align(p)); 454773Speter putdot( filename , line ); 4558758Speter break; 4568758Speter } 4578758Speter # endif PC 458773Speter return (p); /* Used by for statement */ 459773Speter } 460773Speter 461773Speter /* 462773Speter * if expr then stat [ else stat ] 463773Speter */ 464*15941Smckusick ifop(if_n) 465*15941Smckusick IF_NODE *if_n; 466773Speter { 467773Speter register struct nl *p; 468773Speter register l1, l2; /* l1 is start of else, l2 is end of else */ 4693079Smckusic int goc; 4703079Smckusic bool nr; 471773Speter 472773Speter goc = gocnt; 473773Speter putline(); 474*15941Smckusick p = rvalue(if_n->cond_expr, NLNIL , RREQ ); 475773Speter if (p == NIL) { 476*15941Smckusick statement(if_n->then_stmnt); 477*15941Smckusick noreach = FALSE; 478*15941Smckusick statement(if_n->else_stmnt); 479*15941Smckusick noreach = FALSE; 480773Speter return; 481773Speter } 482773Speter if (isnta(p, "b")) { 483773Speter error("Type of expression in if statement must be Boolean, not %s", nameof(p)); 484*15941Smckusick statement(if_n->then_stmnt); 485*15941Smckusick noreach = FALSE; 486*15941Smckusick statement(if_n->else_stmnt); 487*15941Smckusick noreach = FALSE; 488773Speter return; 489773Speter } 490773Speter # ifdef OBJ 4913079Smckusic l1 = put(2, O_IF, getlab()); 492773Speter # endif OBJ 493773Speter # ifdef PC 494*15941Smckusick l1 = (int) getlab(); 495*15941Smckusick putleaf( P2ICON , l1 , 0 , P2INT , (char *) 0 ); 496773Speter putop( P2CBRANCH , P2INT ); 497773Speter putdot( filename , line ); 498773Speter # endif PC 499773Speter putcnt(); 500*15941Smckusick statement(if_n->then_stmnt); 501773Speter nr = noreach; 502*15941Smckusick if (if_n->else_stmnt != TR_NIL) { 503773Speter /* 504773Speter * else stat 505773Speter */ 506773Speter --level; 507773Speter ungoto(); 508773Speter ++level; 509773Speter # ifdef OBJ 5103079Smckusic l2 = put(2, O_TRA, getlab()); 511773Speter # endif OBJ 512773Speter # ifdef PC 513*15941Smckusick l2 = (int) getlab(); 514*15941Smckusick putjbr( (long) l2 ); 515773Speter # endif PC 516*15941Smckusick patch((PTR_DCL)l1); 517*15941Smckusick noreach = FALSE; 518*15941Smckusick statement(if_n->else_stmnt); 519*15941Smckusick noreach = (noreach && nr)?TRUE:FALSE; 520773Speter l1 = l2; 521773Speter } else 522*15941Smckusick noreach = FALSE; 523*15941Smckusick patch((PTR_DCL)l1); 524773Speter if (goc != gocnt) 525773Speter putcnt(); 526773Speter } 527773Speter 528773Speter /* 529773Speter * while expr do stat 530773Speter */ 531*15941Smckusick whilop(w_node) 532*15941Smckusick WHI_CAS *w_node; 533773Speter { 534773Speter register struct nl *p; 535*15941Smckusick register char *l1, *l2; 536773Speter int goc; 537773Speter 538773Speter goc = gocnt; 539*15941Smckusick l1 = getlab(); 540*15941Smckusick (void) putlab(l1); 541773Speter putline(); 542*15941Smckusick p = rvalue(w_node->expr, NLNIL , RREQ ); 543*15941Smckusick if (p == NLNIL) { 544*15941Smckusick statement(w_node->stmnt_list); 545*15941Smckusick noreach = FALSE; 546773Speter return; 547773Speter } 548773Speter if (isnta(p, "b")) { 549773Speter error("Type of expression in while statement must be Boolean, not %s", nameof(p)); 550*15941Smckusick statement(w_node->stmnt_list); 551*15941Smckusick noreach = FALSE; 552773Speter return; 553773Speter } 554773Speter l2 = getlab(); 555773Speter # ifdef OBJ 556*15941Smckusick (void) put(2, O_IF, l2); 557773Speter # endif OBJ 558773Speter # ifdef PC 559*15941Smckusick putleaf( P2ICON , (int) l2 , 0 , P2INT , (char *) 0 ); 560773Speter putop( P2CBRANCH , P2INT ); 561773Speter putdot( filename , line ); 562773Speter # endif PC 563773Speter putcnt(); 564*15941Smckusick statement(w_node->stmnt_list); 565773Speter # ifdef OBJ 566*15941Smckusick (void) put(2, O_TRA, l1); 567773Speter # endif OBJ 568773Speter # ifdef PC 569*15941Smckusick putjbr( (long) l1 ); 570773Speter # endif PC 571*15941Smckusick patch((PTR_DCL) l2); 572773Speter if (goc != gocnt) 573773Speter putcnt(); 574773Speter } 575773Speter 576773Speter /* 577773Speter * repeat stat* until expr 578773Speter */ 579773Speter repop(r) 580*15941Smckusick REPEAT *r; 581773Speter { 582773Speter register struct nl *p; 583773Speter register l; 584773Speter int goc; 585773Speter 586773Speter goc = gocnt; 587*15941Smckusick l = (int) putlab(getlab()); 588773Speter putcnt(); 589*15941Smckusick statlist(r->stmnt_list); 590*15941Smckusick line = r->line_no; 591*15941Smckusick p = rvalue(r->term_expr, NLNIL , RREQ ); 592*15941Smckusick if (p == NLNIL) 593773Speter return; 594773Speter if (isnta(p,"b")) { 595773Speter error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p)); 596773Speter return; 597773Speter } 598773Speter # ifdef OBJ 599*15941Smckusick (void) put(2, O_IF, l); 600773Speter # endif OBJ 601773Speter # ifdef PC 602*15941Smckusick putleaf( P2ICON , l , 0 , P2INT , (char *) 0 ); 603773Speter putop( P2CBRANCH , P2INT ); 604773Speter putdot( filename , line ); 605773Speter # endif PC 606773Speter if (goc != gocnt) 607773Speter putcnt(); 608773Speter } 609