1773Speter /* Copyright (c) 1979 Regents of the University of California */ 2773Speter 3*3079Smckusic static char sccsid[] = "@(#)stat.c 1.3 03/08/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: 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 */ 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 182*3079Smckusic put(2, 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) 197*3079Smckusic put(2, 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 249*3079Smckusic put(2, 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 319*3079Smckusic put(2, O_LV | bn << 8+INDX, (int)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; 356*3079Smckusic int w; 357773Speter 358773Speter if (r == NIL) 359773Speter return (NIL); 360773Speter if (p == NIL) { 361773Speter # ifdef OBJ 362773Speter p = lvalue(r[2], MOD|ASGN|NOUSE , LREQ ); 363*3079Smckusic w = width(p); 364773Speter # endif OBJ 365773Speter # ifdef PC 366773Speter /* 367773Speter * since the second pass knows that it should reference 368773Speter * the lefthandside of asignments, what i need here is 369773Speter * an rvalue. 370773Speter */ 371773Speter p = lvalue( r[2] , MOD|ASGN|NOUSE , RREQ ); 372773Speter # endif PC 373773Speter if ( p == NIL ) { 374773Speter rvalue( r[3] , NIL , RREQ ); 375773Speter return NIL; 376773Speter } 377773Speter } 378773Speter # ifdef OBJ 379*3079Smckusic /* 380*3079Smckusic * assigning to the return value, which is at least 381*3079Smckusic * of width two since it resides on the stack 382*3079Smckusic */ 383*3079Smckusic else { 384*3079Smckusic w = width(p); 385*3079Smckusic if (w < 2) 386*3079Smckusic w = 2; 387*3079Smckusic } 388773Speter p1 = rvalue(r[3], p , RREQ ); 389773Speter # endif OBJ 390773Speter # ifdef PC 391773Speter /* 392773Speter * if this is a scalar assignment, 393773Speter * then i want to rvalue the righthandside. 394773Speter * if this is a structure assignment, 395773Speter * then i want an lvalue to the righthandside. 396773Speter * that's what the intermediate form sez. 397773Speter */ 398773Speter switch ( classify( p ) ) { 399773Speter case TINT: 400773Speter case TCHAR: 401773Speter case TBOOL: 402773Speter case TSCAL: 403773Speter precheck( p , "_RANG4" , "_RSNG4" ); 404773Speter case TDOUBLE: 405773Speter case TPTR: 406773Speter p1 = rvalue( r[3] , p , RREQ ); 407773Speter break; 408773Speter default: 409773Speter p1 = rvalue( r[3] , p , LREQ ); 410773Speter break; 411773Speter } 412773Speter # endif PC 413773Speter if (p1 == NIL) 414773Speter return (NIL); 415773Speter if (incompat(p1, p, r[3])) { 416773Speter cerror("Type of expression clashed with type of variable in assignment"); 417773Speter return (NIL); 418773Speter } 419773Speter switch (classify(p)) { 420773Speter case TINT: 421773Speter case TBOOL: 422773Speter case TCHAR: 423773Speter case TSCAL: 424773Speter # ifdef OBJ 425773Speter rangechk(p, p1); 426773Speter # endif OBJ 427773Speter # ifdef PC 428773Speter postcheck( p ); 429773Speter # endif PC 430773Speter case TDOUBLE: 431773Speter case TPTR: 432773Speter # ifdef OBJ 433*3079Smckusic gen(O_AS2, O_AS2, w, width(p1)); 434773Speter # endif OBJ 435773Speter # ifdef PC 436773Speter putop( P2ASSIGN , p2type( p ) ); 437773Speter putdot( filename , line ); 438773Speter # endif PC 439773Speter break; 440773Speter default: 441773Speter # ifdef OBJ 442*3079Smckusic put(2, O_AS, w); 443773Speter # endif OBJ 444773Speter # ifdef PC 445773Speter putstrop( P2STASG , p2type( p ) 446773Speter , lwidth( p ) , align( p ) ); 447773Speter putdot( filename , line ); 448773Speter # endif PC 449773Speter } 450773Speter return (p); /* Used by for statement */ 451773Speter } 452773Speter 453773Speter /* 454773Speter * if expr then stat [ else stat ] 455773Speter */ 456773Speter ifop(r) 457773Speter int *r; 458773Speter { 459773Speter register struct nl *p; 460773Speter register l1, l2; /* l1 is start of else, l2 is end of else */ 461*3079Smckusic int goc; 462*3079Smckusic bool nr; 463773Speter 464773Speter goc = gocnt; 465773Speter if (r == NIL) 466773Speter return; 467773Speter putline(); 468773Speter p = rvalue(r[2], NIL , RREQ ); 469773Speter if (p == NIL) { 470773Speter statement(r[3]); 471773Speter noreach = 0; 472773Speter statement(r[4]); 473773Speter noreach = 0; 474773Speter return; 475773Speter } 476773Speter if (isnta(p, "b")) { 477773Speter error("Type of expression in if statement must be Boolean, not %s", nameof(p)); 478773Speter statement(r[3]); 479773Speter noreach = 0; 480773Speter statement(r[4]); 481773Speter noreach = 0; 482773Speter return; 483773Speter } 484773Speter # ifdef OBJ 485*3079Smckusic l1 = put(2, O_IF, getlab()); 486773Speter # endif OBJ 487773Speter # ifdef PC 488773Speter l1 = getlab(); 489773Speter putleaf( P2ICON , l1 , 0 , P2INT , 0 ); 490773Speter putop( P2CBRANCH , P2INT ); 491773Speter putdot( filename , line ); 492773Speter # endif PC 493773Speter putcnt(); 494773Speter statement(r[3]); 495773Speter nr = noreach; 496773Speter if (r[4] != NIL) { 497773Speter /* 498773Speter * else stat 499773Speter */ 500773Speter --level; 501773Speter ungoto(); 502773Speter ++level; 503773Speter # ifdef OBJ 504*3079Smckusic l2 = put(2, O_TRA, getlab()); 505773Speter # endif OBJ 506773Speter # ifdef PC 507773Speter l2 = getlab(); 508773Speter putjbr( l2 ); 509773Speter # endif PC 510773Speter patch(l1); 511773Speter noreach = 0; 512773Speter statement(r[4]); 513*3079Smckusic noreach = (noreach && nr); 514773Speter l1 = l2; 515773Speter } else 516773Speter noreach = 0; 517773Speter patch(l1); 518773Speter if (goc != gocnt) 519773Speter putcnt(); 520773Speter } 521773Speter 522773Speter /* 523773Speter * while expr do stat 524773Speter */ 525773Speter whilop(r) 526773Speter int *r; 527773Speter { 528773Speter register struct nl *p; 529773Speter register l1, l2; 530773Speter int goc; 531773Speter 532773Speter goc = gocnt; 533773Speter if (r == NIL) 534773Speter return; 535773Speter putlab(l1 = getlab()); 536773Speter putline(); 537773Speter p = rvalue(r[2], NIL , RREQ ); 538773Speter if (p == NIL) { 539773Speter statement(r[3]); 540773Speter noreach = 0; 541773Speter return; 542773Speter } 543773Speter if (isnta(p, "b")) { 544773Speter error("Type of expression in while statement must be Boolean, not %s", nameof(p)); 545773Speter statement(r[3]); 546773Speter noreach = 0; 547773Speter return; 548773Speter } 549773Speter l2 = getlab(); 550773Speter # ifdef OBJ 551*3079Smckusic put(2, O_IF, l2); 552773Speter # endif OBJ 553773Speter # ifdef PC 554773Speter putleaf( P2ICON , l2 , 0 , P2INT , 0 ); 555773Speter putop( P2CBRANCH , P2INT ); 556773Speter putdot( filename , line ); 557773Speter # endif PC 558773Speter putcnt(); 559773Speter statement(r[3]); 560773Speter # ifdef OBJ 561*3079Smckusic put(2, O_TRA, l1); 562773Speter # endif OBJ 563773Speter # ifdef PC 564773Speter putjbr( l1 ); 565773Speter # endif PC 566773Speter patch(l2); 567773Speter if (goc != gocnt) 568773Speter putcnt(); 569773Speter } 570773Speter 571773Speter /* 572773Speter * repeat stat* until expr 573773Speter */ 574773Speter repop(r) 575773Speter int *r; 576773Speter { 577773Speter register struct nl *p; 578773Speter register l; 579773Speter int goc; 580773Speter 581773Speter goc = gocnt; 582773Speter if (r == NIL) 583773Speter return; 584773Speter l = putlab(getlab()); 585773Speter putcnt(); 586773Speter statlist(r[2]); 587773Speter line = r[1]; 588773Speter p = rvalue(r[3], NIL , RREQ ); 589773Speter if (p == NIL) 590773Speter return; 591773Speter if (isnta(p,"b")) { 592773Speter error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p)); 593773Speter return; 594773Speter } 595773Speter # ifdef OBJ 596*3079Smckusic put(2, O_IF, l); 597773Speter # endif OBJ 598773Speter # ifdef PC 599773Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 600773Speter putop( P2CBRANCH , P2INT ); 601773Speter putdot( filename , line ); 602773Speter # endif PC 603773Speter if (goc != gocnt) 604773Speter putcnt(); 605773Speter } 606773Speter 607773Speter /* 608773Speter * assert expr 609773Speter */ 610773Speter asrtop(r) 611773Speter register int *r; 612773Speter { 613773Speter register struct nl *q; 614773Speter 615773Speter if (opt('s')) { 616773Speter standard(); 617773Speter error("Assert statement is non-standard"); 618773Speter } 619773Speter if (!opt('t')) 620773Speter return; 621773Speter r = r[2]; 622773Speter # ifdef OBJ 623773Speter q = rvalue((int *) r, NLNIL , RREQ ); 624773Speter # endif OBJ 625773Speter # ifdef PC 626773Speter putleaf( P2ICON , 0 , 0 627773Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ASRT" ); 628773Speter q = stkrval( r , NLNIL , RREQ ); 629773Speter # endif PC 630773Speter if (q == NIL) 631773Speter return; 632773Speter if (isnta(q, "b")) 633773Speter error("Assert expression must be Boolean, not %ss", nameof(q)); 634773Speter # ifdef OBJ 635*3079Smckusic put(1, O_ASRT); 636773Speter # endif OBJ 637773Speter # ifdef PC 638773Speter putop( P2CALL , P2INT ); 639773Speter putdot( filename , line ); 640773Speter # endif PC 641773Speter } 642