1773Speter /* Copyright (c) 1979 Regents of the University of California */ 2773Speter 3*5654Slinton static char sccsid[] = "@(#)stat.c 1.6 02/02/82"; 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 1803835Speter 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); 193*5654Slinton 194*5654Slinton /* 195*5654Slinton * put out line number information for pdx 196*5654Slinton */ 197*5654Slinton lineno(line); 198*5654Slinton 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 ); 215773Speter putleaf( P2ICON , 1 , 0 , P2INT , 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) 234773Speter int *s; 235773Speter { 236773Speter register *p; 237773Speter register struct nl *r; 2383835Speter struct nl *tempnlp; 239773Speter int *swl; 240773Speter 241773Speter putline(); 242773Speter swl = withlist; 243773Speter for (p = s[2]; p != NIL; p = p[2]) { 2443835Speter tempnlp = tmpalloc(sizeof(int *), INT_TYP, REGOK); 245773Speter # ifdef OBJ 2463835Speter put(2, O_LV | cbn <<8+INDX, tempnlp -> value[ NL_OFFS ] ); 247773Speter # endif OBJ 248773Speter # ifdef PC 2493835Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 2503835Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 251773Speter # endif PC 252773Speter r = lvalue(p[1], MOD , LREQ ); 253773Speter if (r == NIL) 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 } 2593835Speter r = defnl(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 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 withlist = swl; 275773Speter } 276773Speter 277773Speter extern flagwas; 278773Speter /* 279773Speter * var := expr 280773Speter */ 281773Speter asgnop(r) 282773Speter int *r; 283773Speter { 284773Speter register struct nl *p; 285773Speter register *av; 286773Speter 287773Speter if (r == NIL) 288773Speter return (NIL); 289773Speter /* 290773Speter * Asgnop's only function is 291773Speter * to handle function variable 292773Speter * assignments. All other assignment 293773Speter * stuff is handled by asgnop1. 294773Speter * the if below checks for unqualified lefthandside: 295773Speter * necessary for fvars. 296773Speter */ 297773Speter av = r[2]; 298773Speter if (av != NIL && av[0] == T_VAR && av[3] == NIL) { 299773Speter p = lookup1(av[2]); 300773Speter if (p != NIL) 301773Speter p->nl_flags = flagwas; 302773Speter if (p != NIL && p->class == FVAR) { 303773Speter /* 304773Speter * Give asgnop1 the func 305773Speter * which is the chain of 306773Speter * the FVAR. 307773Speter */ 308773Speter p->nl_flags |= NUSED|NMOD; 309773Speter p = p->chain; 310773Speter if (p == NIL) { 311773Speter rvalue(r[3], NIL , RREQ ); 312773Speter return; 313773Speter } 314773Speter # ifdef OBJ 3153079Smckusic put(2, O_LV | bn << 8+INDX, (int)p->value[NL_OFFS]); 316773Speter if (isa(p->type, "i") && width(p->type) == 1) 317773Speter asgnop1(r, nl+T2INT); 318773Speter else 319773Speter asgnop1(r, p->type); 320773Speter # endif OBJ 321773Speter # ifdef PC 322773Speter /* 323773Speter * this should be the lvalue of the fvar, 324773Speter * but since the second pass knows to use 325773Speter * the address of the left operand of an 326773Speter * assignment, what i want here is an rvalue. 327773Speter * see note in funchdr about fvar allocation. 328773Speter */ 329773Speter p = p -> ptr[ NL_FVAR ]; 3303835Speter putRV( p -> symbol , bn , p -> value[ NL_OFFS ] , 3313835Speter p -> extra_flags , p2type( p -> type ) ); 332773Speter asgnop1( r , p -> type ); 333773Speter # endif PC 334773Speter return; 335773Speter } 336773Speter } 337773Speter asgnop1(r, NIL); 338773Speter } 339773Speter 340773Speter /* 341773Speter * Asgnop1 handles all assignments. 342773Speter * If p is not nil then we are assigning 343773Speter * to a function variable, otherwise 344773Speter * we look the variable up ourselves. 345773Speter */ 346773Speter struct nl * 347773Speter asgnop1(r, p) 348773Speter int *r; 349773Speter register struct nl *p; 350773Speter { 351773Speter register struct nl *p1; 3523079Smckusic int w; 353773Speter 354773Speter if (r == NIL) 355773Speter return (NIL); 356773Speter if (p == NIL) { 357773Speter # ifdef OBJ 358773Speter p = lvalue(r[2], MOD|ASGN|NOUSE , LREQ ); 3593079Smckusic w = width(p); 360773Speter # endif OBJ 361773Speter # ifdef PC 362773Speter /* 363773Speter * since the second pass knows that it should reference 364773Speter * the lefthandside of asignments, what i need here is 365773Speter * an rvalue. 366773Speter */ 367773Speter p = lvalue( r[2] , MOD|ASGN|NOUSE , RREQ ); 368773Speter # endif PC 369773Speter if ( p == NIL ) { 370773Speter rvalue( r[3] , NIL , RREQ ); 371773Speter return NIL; 372773Speter } 373773Speter } 374773Speter # ifdef OBJ 3753079Smckusic /* 3763079Smckusic * assigning to the return value, which is at least 3773079Smckusic * of width two since it resides on the stack 3783079Smckusic */ 3793079Smckusic else { 3803079Smckusic w = width(p); 3813079Smckusic if (w < 2) 3823079Smckusic w = 2; 3833079Smckusic } 384773Speter p1 = rvalue(r[3], p , RREQ ); 385773Speter # endif OBJ 386773Speter # ifdef PC 387773Speter /* 388773Speter * if this is a scalar assignment, 389773Speter * then i want to rvalue the righthandside. 390773Speter * if this is a structure assignment, 391773Speter * then i want an lvalue to the righthandside. 392773Speter * that's what the intermediate form sez. 393773Speter */ 394773Speter switch ( classify( p ) ) { 395773Speter case TINT: 396773Speter case TCHAR: 397773Speter case TBOOL: 398773Speter case TSCAL: 399773Speter precheck( p , "_RANG4" , "_RSNG4" ); 400773Speter case TDOUBLE: 401773Speter case TPTR: 402773Speter p1 = rvalue( r[3] , p , RREQ ); 403773Speter break; 404773Speter default: 405773Speter p1 = rvalue( r[3] , p , LREQ ); 406773Speter break; 407773Speter } 408773Speter # endif PC 409773Speter if (p1 == NIL) 410773Speter return (NIL); 411773Speter if (incompat(p1, p, r[3])) { 412773Speter cerror("Type of expression clashed with type of variable in assignment"); 413773Speter return (NIL); 414773Speter } 415773Speter switch (classify(p)) { 416773Speter case TINT: 417773Speter case TBOOL: 418773Speter case TCHAR: 419773Speter case TSCAL: 420773Speter # ifdef OBJ 421773Speter rangechk(p, p1); 422773Speter # endif OBJ 423773Speter # ifdef PC 424773Speter postcheck( p ); 425773Speter # endif PC 426773Speter case TDOUBLE: 427773Speter case TPTR: 428773Speter # ifdef OBJ 4293079Smckusic gen(O_AS2, O_AS2, w, width(p1)); 430773Speter # endif OBJ 431773Speter # ifdef PC 432773Speter putop( P2ASSIGN , p2type( p ) ); 433773Speter putdot( filename , line ); 434773Speter # endif PC 435773Speter break; 436773Speter default: 437773Speter # ifdef OBJ 4383079Smckusic put(2, O_AS, w); 439773Speter # endif OBJ 440773Speter # ifdef PC 441773Speter putstrop( P2STASG , p2type( p ) 442773Speter , lwidth( p ) , align( p ) ); 443773Speter putdot( filename , line ); 444773Speter # endif PC 445773Speter } 446773Speter return (p); /* Used by for statement */ 447773Speter } 448773Speter 449773Speter /* 450773Speter * if expr then stat [ else stat ] 451773Speter */ 452773Speter ifop(r) 453773Speter int *r; 454773Speter { 455773Speter register struct nl *p; 456773Speter register l1, l2; /* l1 is start of else, l2 is end of else */ 4573079Smckusic int goc; 4583079Smckusic bool nr; 459773Speter 460773Speter goc = gocnt; 461773Speter if (r == NIL) 462773Speter return; 463773Speter putline(); 464773Speter p = rvalue(r[2], NIL , RREQ ); 465773Speter if (p == NIL) { 466773Speter statement(r[3]); 467773Speter noreach = 0; 468773Speter statement(r[4]); 469773Speter noreach = 0; 470773Speter return; 471773Speter } 472773Speter if (isnta(p, "b")) { 473773Speter error("Type of expression in if statement must be Boolean, not %s", nameof(p)); 474773Speter statement(r[3]); 475773Speter noreach = 0; 476773Speter statement(r[4]); 477773Speter noreach = 0; 478773Speter return; 479773Speter } 480773Speter # ifdef OBJ 4813079Smckusic l1 = put(2, O_IF, getlab()); 482773Speter # endif OBJ 483773Speter # ifdef PC 484773Speter l1 = getlab(); 485773Speter putleaf( P2ICON , l1 , 0 , P2INT , 0 ); 486773Speter putop( P2CBRANCH , P2INT ); 487773Speter putdot( filename , line ); 488773Speter # endif PC 489773Speter putcnt(); 490773Speter statement(r[3]); 491773Speter nr = noreach; 492773Speter if (r[4] != NIL) { 493773Speter /* 494773Speter * else stat 495773Speter */ 496773Speter --level; 497773Speter ungoto(); 498773Speter ++level; 499773Speter # ifdef OBJ 5003079Smckusic l2 = put(2, O_TRA, getlab()); 501773Speter # endif OBJ 502773Speter # ifdef PC 503773Speter l2 = getlab(); 504773Speter putjbr( l2 ); 505773Speter # endif PC 506773Speter patch(l1); 507773Speter noreach = 0; 508773Speter statement(r[4]); 5093079Smckusic noreach = (noreach && nr); 510773Speter l1 = l2; 511773Speter } else 512773Speter noreach = 0; 513773Speter patch(l1); 514773Speter if (goc != gocnt) 515773Speter putcnt(); 516773Speter } 517773Speter 518773Speter /* 519773Speter * while expr do stat 520773Speter */ 521773Speter whilop(r) 522773Speter int *r; 523773Speter { 524773Speter register struct nl *p; 525773Speter register l1, l2; 526773Speter int goc; 527773Speter 528773Speter goc = gocnt; 529773Speter if (r == NIL) 530773Speter return; 531773Speter putlab(l1 = getlab()); 532773Speter putline(); 533773Speter p = rvalue(r[2], NIL , RREQ ); 534773Speter if (p == NIL) { 535773Speter statement(r[3]); 536773Speter noreach = 0; 537773Speter return; 538773Speter } 539773Speter if (isnta(p, "b")) { 540773Speter error("Type of expression in while statement must be Boolean, not %s", nameof(p)); 541773Speter statement(r[3]); 542773Speter noreach = 0; 543773Speter return; 544773Speter } 545773Speter l2 = getlab(); 546773Speter # ifdef OBJ 5473079Smckusic put(2, O_IF, l2); 548773Speter # endif OBJ 549773Speter # ifdef PC 550773Speter putleaf( P2ICON , l2 , 0 , P2INT , 0 ); 551773Speter putop( P2CBRANCH , P2INT ); 552773Speter putdot( filename , line ); 553773Speter # endif PC 554773Speter putcnt(); 555773Speter statement(r[3]); 556773Speter # ifdef OBJ 5573079Smckusic put(2, O_TRA, l1); 558773Speter # endif OBJ 559773Speter # ifdef PC 560773Speter putjbr( l1 ); 561773Speter # endif PC 562773Speter patch(l2); 563773Speter if (goc != gocnt) 564773Speter putcnt(); 565773Speter } 566773Speter 567773Speter /* 568773Speter * repeat stat* until expr 569773Speter */ 570773Speter repop(r) 571773Speter int *r; 572773Speter { 573773Speter register struct nl *p; 574773Speter register l; 575773Speter int goc; 576773Speter 577773Speter goc = gocnt; 578773Speter if (r == NIL) 579773Speter return; 580773Speter l = putlab(getlab()); 581773Speter putcnt(); 582773Speter statlist(r[2]); 583773Speter line = r[1]; 584773Speter p = rvalue(r[3], NIL , RREQ ); 585773Speter if (p == NIL) 586773Speter return; 587773Speter if (isnta(p,"b")) { 588773Speter error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p)); 589773Speter return; 590773Speter } 591773Speter # ifdef OBJ 5923079Smckusic put(2, O_IF, l); 593773Speter # endif OBJ 594773Speter # ifdef PC 595773Speter putleaf( P2ICON , l , 0 , P2INT , 0 ); 596773Speter putop( P2CBRANCH , P2INT ); 597773Speter putdot( filename , line ); 598773Speter # endif PC 599773Speter if (goc != gocnt) 600773Speter putcnt(); 601773Speter } 602773Speter 603773Speter /* 604773Speter * assert expr 605773Speter */ 606773Speter asrtop(r) 607773Speter register int *r; 608773Speter { 609773Speter register struct nl *q; 610773Speter 611773Speter if (opt('s')) { 612773Speter standard(); 613773Speter error("Assert statement is non-standard"); 614773Speter } 615773Speter if (!opt('t')) 616773Speter return; 617773Speter r = r[2]; 618773Speter # ifdef OBJ 619773Speter q = rvalue((int *) r, NLNIL , RREQ ); 620773Speter # endif OBJ 621773Speter # ifdef PC 622773Speter putleaf( P2ICON , 0 , 0 623773Speter , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ASRT" ); 624773Speter q = stkrval( r , NLNIL , RREQ ); 625773Speter # endif PC 626773Speter if (q == NIL) 627773Speter return; 628773Speter if (isnta(q, "b")) 629773Speter error("Assert expression must be Boolean, not %ss", nameof(q)); 630773Speter # ifdef OBJ 6313079Smckusic put(1, O_ASRT); 632773Speter # endif OBJ 633773Speter # ifdef PC 634773Speter putop( P2CALL , P2INT ); 635773Speter putdot( filename , line ); 636773Speter # endif PC 637773Speter } 638