1773Speter /* Copyright (c) 1979 Regents of the University of California */ 2773Speter 3*3835Speter static char sccsid[] = "@(#)stat.c 1.5 06/01/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; 383228Smckusic struct tmps soffset; 39773Speter 40773Speter s = r; 41773Speter snlp = nlp; 423228Smckusic 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 */ 1383228Smckusic 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 180*3835Speter putRV( PCPCOUNT , 0 , counter * sizeof (long) , NGLOBAL , 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 { 208*3835Speter putRV( STMTCOUNT , 0 , 0 , NGLOBAL , 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; 232*3835Speter struct nl *tempnlp; 233773Speter int *swl; 234773Speter 235773Speter putline(); 236773Speter swl = withlist; 237773Speter for (p = s[2]; p != NIL; p = p[2]) { 238*3835Speter tempnlp = tmpalloc(sizeof(int *), INT_TYP, REGOK); 239773Speter # ifdef OBJ 240*3835Speter put(2, O_LV | cbn <<8+INDX, tempnlp -> value[ NL_OFFS ] ); 241773Speter # endif OBJ 242773Speter # ifdef PC 243*3835Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 244*3835Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 245773Speter # endif PC 246773Speter r = lvalue(p[1], MOD , LREQ ); 247773Speter if (r == NIL) 248773Speter continue; 249773Speter if (r->class != RECORD) { 250773Speter error("Variable in with statement refers to %s, not to a record", nameof(r)); 251773Speter continue; 252773Speter } 253*3835Speter r = defnl(0, WITHPTR, r, tempnlp -> value[ NL_OFFS ] ); 254*3835Speter # ifdef PC 255*3835Speter r -> extra_flags |= tempnlp -> extra_flags; 256*3835Speter # endif PC 257773Speter r->nl_next = withlist; 258773Speter withlist = r; 259773Speter # ifdef OBJ 260773Speter put(1, PTR_AS); 261773Speter # endif OBJ 262773Speter # ifdef PC 263773Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 264773Speter putdot( filename , line ); 265773Speter # endif PC 266773Speter } 267773Speter statement(s[3]); 268773Speter withlist = swl; 269773Speter } 270773Speter 271773Speter extern flagwas; 272773Speter /* 273773Speter * var := expr 274773Speter */ 275773Speter asgnop(r) 276773Speter int *r; 277773Speter { 278773Speter register struct nl *p; 279773Speter register *av; 280773Speter 281773Speter if (r == NIL) 282773Speter return (NIL); 283773Speter /* 284773Speter * Asgnop's only function is 285773Speter * to handle function variable 286773Speter * assignments. All other assignment 287773Speter * stuff is handled by asgnop1. 288773Speter * the if below checks for unqualified lefthandside: 289773Speter * necessary for fvars. 290773Speter */ 291773Speter av = r[2]; 292773Speter if (av != NIL && av[0] == T_VAR && av[3] == NIL) { 293773Speter p = lookup1(av[2]); 294773Speter if (p != NIL) 295773Speter p->nl_flags = flagwas; 296773Speter if (p != NIL && p->class == FVAR) { 297773Speter /* 298773Speter * Give asgnop1 the func 299773Speter * which is the chain of 300773Speter * the FVAR. 301773Speter */ 302773Speter p->nl_flags |= NUSED|NMOD; 303773Speter p = p->chain; 304773Speter if (p == NIL) { 305773Speter rvalue(r[3], NIL , RREQ ); 306773Speter return; 307773Speter } 308773Speter # ifdef OBJ 3093079Smckusic put(2, O_LV | bn << 8+INDX, (int)p->value[NL_OFFS]); 310773Speter if (isa(p->type, "i") && width(p->type) == 1) 311773Speter asgnop1(r, nl+T2INT); 312773Speter else 313773Speter asgnop1(r, p->type); 314773Speter # endif OBJ 315773Speter # ifdef PC 316773Speter /* 317773Speter * this should be the lvalue of the fvar, 318773Speter * but since the second pass knows to use 319773Speter * the address of the left operand of an 320773Speter * assignment, what i want here is an rvalue. 321773Speter * see note in funchdr about fvar allocation. 322773Speter */ 323773Speter p = p -> ptr[ NL_FVAR ]; 324*3835Speter putRV( p -> symbol , bn , p -> value[ NL_OFFS ] , 325*3835Speter p -> extra_flags , p2type( p -> type ) ); 326773Speter asgnop1( r , p -> type ); 327773Speter # endif PC 328773Speter return; 329773Speter } 330773Speter } 331773Speter asgnop1(r, NIL); 332773Speter } 333773Speter 334773Speter /* 335773Speter * Asgnop1 handles all assignments. 336773Speter * If p is not nil then we are assigning 337773Speter * to a function variable, otherwise 338773Speter * we look the variable up ourselves. 339773Speter */ 340773Speter struct nl * 341773Speter asgnop1(r, p) 342773Speter int *r; 343773Speter register struct nl *p; 344773Speter { 345773Speter register struct nl *p1; 3463079Smckusic int w; 347773Speter 348773Speter if (r == NIL) 349773Speter return (NIL); 350773Speter if (p == NIL) { 351773Speter # ifdef OBJ 352773Speter p = lvalue(r[2], MOD|ASGN|NOUSE , LREQ ); 3533079Smckusic w = width(p); 354773Speter # endif OBJ 355773Speter # ifdef PC 356773Speter /* 357773Speter * since the second pass knows that it should reference 358773Speter * the lefthandside of asignments, what i need here is 359773Speter * an rvalue. 360773Speter */ 361773Speter p = lvalue( r[2] , MOD|ASGN|NOUSE , RREQ ); 362773Speter # endif PC 363773Speter if ( p == NIL ) { 364773Speter rvalue( r[3] , NIL , RREQ ); 365773Speter return NIL; 366773Speter } 367773Speter } 368773Speter # ifdef OBJ 3693079Smckusic /* 3703079Smckusic * assigning to the return value, which is at least 3713079Smckusic * of width two since it resides on the stack 3723079Smckusic */ 3733079Smckusic else { 3743079Smckusic w = width(p); 3753079Smckusic if (w < 2) 3763079Smckusic w = 2; 3773079Smckusic } 378773Speter p1 = rvalue(r[3], p , RREQ ); 379773Speter # endif OBJ 380773Speter # ifdef PC 381773Speter /* 382773Speter * if this is a scalar assignment, 383773Speter * then i want to rvalue the righthandside. 384773Speter * if this is a structure assignment, 385773Speter * then i want an lvalue to the righthandside. 386773Speter * that's what the intermediate form sez. 387773Speter */ 388773Speter switch ( classify( p ) ) { 389773Speter case TINT: 390773Speter case TCHAR: 391773Speter case TBOOL: 392773Speter case TSCAL: 393773Speter precheck( p , "_RANG4" , "_RSNG4" ); 394773Speter case TDOUBLE: 395773Speter case TPTR: 396773Speter p1 = rvalue( r[3] , p , RREQ ); 397773Speter break; 398773Speter default: 399773Speter p1 = rvalue( r[3] , p , LREQ ); 400773Speter break; 401773Speter } 402773Speter # endif PC 403773Speter if (p1 == NIL) 404773Speter return (NIL); 405773Speter if (incompat(p1, p, r[3])) { 406773Speter cerror("Type of expression clashed with type of variable in assignment"); 407773Speter return (NIL); 408773Speter } 409773Speter switch (classify(p)) { 410773Speter case TINT: 411773Speter case TBOOL: 412773Speter case TCHAR: 413773Speter case TSCAL: 414773Speter # ifdef OBJ 415773Speter rangechk(p, p1); 416773Speter # endif OBJ 417773Speter # ifdef PC 418773Speter postcheck( p ); 419773Speter # endif PC 420773Speter case TDOUBLE: 421773Speter case TPTR: 422773Speter # ifdef OBJ 4233079Smckusic gen(O_AS2, O_AS2, w, width(p1)); 424773Speter # endif OBJ 425773Speter # ifdef PC 426773Speter putop( P2ASSIGN , p2type( p ) ); 427773Speter putdot( filename , line ); 428773Speter # endif PC 429773Speter break; 430773Speter default: 431773Speter # ifdef OBJ 4323079Smckusic put(2, O_AS, w); 433773Speter # endif OBJ 434773Speter # ifdef PC 435773Speter putstrop( P2STASG , p2type( p ) 436773Speter , lwidth( p ) , align( p ) ); 437773Speter putdot( filename , line ); 438773Speter # endif PC 439773Speter } 440773Speter return (p); /* Used by for statement */ 441773Speter } 442773Speter 443773Speter /* 444773Speter * if expr then stat [ else stat ] 445773Speter */ 446773Speter ifop(r) 447773Speter int *r; 448773Speter { 449773Speter register struct nl *p; 450773Speter register l1, l2; /* l1 is start of else, l2 is end of else */ 4513079Smckusic int goc; 4523079Smckusic bool nr; 453773Speter 454773Speter goc = gocnt; 455773Speter if (r == NIL) 456773Speter return; 457773Speter putline(); 458773Speter p = rvalue(r[2], NIL , RREQ ); 459773Speter if (p == NIL) { 460773Speter statement(r[3]); 461773Speter noreach = 0; 462773Speter statement(r[4]); 463773Speter noreach = 0; 464773Speter return; 465773Speter } 466773Speter if (isnta(p, "b")) { 467773Speter error("Type of expression in if statement must be Boolean, not %s", nameof(p)); 468773Speter statement(r[3]); 469773Speter noreach = 0; 470773Speter statement(r[4]); 471773Speter noreach = 0; 472773Speter return; 473773Speter } 474773Speter # ifdef OBJ 4753079Smckusic l1 = put(2, O_IF, getlab()); 476773Speter # endif OBJ 477773Speter # ifdef PC 478773Speter l1 = getlab(); 479773Speter putleaf( P2ICON , l1 , 0 , P2INT , 0 ); 480773Speter putop( P2CBRANCH , P2INT ); 481773Speter putdot( filename , line ); 482773Speter # endif PC 483773Speter putcnt(); 484773Speter statement(r[3]); 485773Speter nr = noreach; 486773Speter if (r[4] != NIL) { 487773Speter /* 488773Speter * else stat 489773Speter */ 490773Speter --level; 491773Speter ungoto(); 492773Speter ++level; 493773Speter # ifdef OBJ 4943079Smckusic l2 = put(2, O_TRA, getlab()); 495773Speter # endif OBJ 496773Speter # ifdef PC 497773Speter l2 = getlab(); 498773Speter putjbr( l2 ); 499773Speter # endif PC 500773Speter patch(l1); 501773Speter noreach = 0; 502773Speter statement(r[4]); 5033079Smckusic noreach = (noreach && nr); 504773Speter l1 = l2; 505773Speter } else 506773Speter noreach = 0; 507773Speter patch(l1); 508773Speter if (goc != gocnt) 509773Speter putcnt(); 510773Speter } 511773Speter 512773Speter /* 513773Speter * while expr do stat 514773Speter */ 515773Speter whilop(r) 516773Speter int *r; 517773Speter { 518773Speter register struct nl *p; 519773Speter register l1, l2; 520773Speter int goc; 521773Speter 522773Speter goc = gocnt; 523773Speter if (r == NIL) 524773Speter return; 525773Speter putlab(l1 = getlab()); 526773Speter putline(); 527773Speter p = rvalue(r[2], NIL , RREQ ); 528773Speter if (p == NIL) { 529773Speter statement(r[3]); 530773Speter noreach = 0; 531773Speter return; 532773Speter } 533773Speter if (isnta(p, "b")) { 534773Speter error("Type of expression in while statement must be Boolean, not %s", nameof(p)); 535773Speter statement(r[3]); 536773Speter noreach = 0; 537773Speter return; 538773Speter } 539773Speter l2 = getlab(); 540773Speter # ifdef OBJ 5413079Smckusic put(2, O_IF, l2); 542773Speter # endif OBJ 543773Speter # ifdef PC 544773Speter putleaf( P2ICON , l2 , 0 , P2INT , 0 ); 545773Speter putop( P2CBRANCH , P2INT ); 546773Speter putdot( filename , line ); 547773Speter # endif PC 548773Speter putcnt(); 549773Speter statement(r[3]); 550773Speter # ifdef OBJ 5513079Smckusic put(2, O_TRA, l1); 552773Speter # endif OBJ 553773Speter # ifdef PC 554773Speter putjbr( l1 ); 555773Speter # endif PC 556773Speter patch(l2); 557773Speter if (goc != gocnt) 558773Speter putcnt(); 559773Speter } 560773Speter 561773Speter /* 562773Speter * repeat stat* until expr 563773Speter */ 564773Speter repop(r) 565773Speter int *r; 566773Speter { 567773Speter register struct nl *p; 568773Speter register l; 569773Speter int goc; 570773Speter 571773Speter goc = gocnt; 572773Speter if (r == NIL) 573773Speter return; 574773Speter l = putlab(getlab()); 575773Speter putcnt(); 576773Speter statlist(r[2]); 577773Speter line = r[1]; 578773Speter p = rvalue(r[3], NIL , RREQ ); 579773Speter if (p == NIL) 580773Speter return; 581773Speter if (isnta(p,"b")) { 582773Speter error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p)); 583773Speter return; 584773Speter } 585773Speter # ifdef OBJ 5863079Smckusic put(2, O_IF, l); 587773Speter # endif OBJ 588773Speter # ifdef PC 589773Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 590773Speter putop( P2CBRANCH , P2INT ); 591773Speter putdot( filename , line ); 592773Speter # endif PC 593773Speter if (goc != gocnt) 594773Speter putcnt(); 595773Speter } 596773Speter 597773Speter /* 598773Speter * assert expr 599773Speter */ 600773Speter asrtop(r) 601773Speter register int *r; 602773Speter { 603773Speter register struct nl *q; 604773Speter 605773Speter if (opt('s')) { 606773Speter standard(); 607773Speter error("Assert statement is non-standard"); 608773Speter } 609773Speter if (!opt('t')) 610773Speter return; 611773Speter r = r[2]; 612773Speter # ifdef OBJ 613773Speter q = rvalue((int *) r, NLNIL , RREQ ); 614773Speter # endif OBJ 615773Speter # ifdef PC 616773Speter putleaf( P2ICON , 0 , 0 617773Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ASRT" ); 618773Speter q = stkrval( r , NLNIL , RREQ ); 619773Speter # endif PC 620773Speter if (q == NIL) 621773Speter return; 622773Speter if (isnta(q, "b")) 623773Speter error("Assert expression must be Boolean, not %ss", nameof(q)); 624773Speter # ifdef OBJ 6253079Smckusic put(1, O_ASRT); 626773Speter # endif OBJ 627773Speter # ifdef PC 628773Speter putop( P2CALL , P2INT ); 629773Speter putdot( filename , line ); 630773Speter # endif PC 631773Speter } 632