1773Speter /* Copyright (c) 1979 Regents of the University of California */ 2773Speter 3*8758Speter static char sccsid[] = "@(#)stat.c 1.8 10/21/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 } 120773Speter --level; 121773Speter if (gotos[cbn]) 122773Speter ungoto(); 123773Speter break; 124773Speter } 125773Speter /* 126773Speter * Free the temporary name list entries defined in 127773Speter * expressions, e.g. STRs, and WITHPTRs from withs. 128773Speter */ 129773Speter nlfree(snlp); 130773Speter /* 131773Speter * free any temporaries allocated for this statement 132773Speter * these come from strings and sets. 133773Speter */ 1343228Smckusic tmpfree(&soffset); 135773Speter } 136773Speter 137773Speter ungoto() 138773Speter { 139773Speter register struct nl *p; 140773Speter 141773Speter for (p = gotos[cbn]; p != NIL; p = p->chain) 142773Speter if ((p->nl_flags & NFORWD) != 0) { 143773Speter if (p->value[NL_GOLEV] != NOTYET) 144773Speter if (p->value[NL_GOLEV] > level) 145773Speter p->value[NL_GOLEV] = level; 146773Speter } else 147773Speter if (p->value[NL_GOLEV] != DEAD) 148773Speter if (p->value[NL_GOLEV] > level) 149773Speter p->value[NL_GOLEV] = DEAD; 150773Speter } 151773Speter 152773Speter putcnt() 153773Speter { 154773Speter 155773Speter if (monflg == 0) { 156773Speter return; 157773Speter } 158773Speter inccnt( getcnt() ); 159773Speter } 160773Speter 161773Speter int 162773Speter getcnt() 163773Speter { 164773Speter 165773Speter return ++cnts; 166773Speter } 167773Speter 168773Speter inccnt( counter ) 169773Speter int counter; 170773Speter { 171773Speter 172773Speter # ifdef OBJ 1733079Smckusic put(2, O_COUNT, counter ); 174773Speter # endif OBJ 175773Speter # ifdef PC 1763835Speter putRV( PCPCOUNT , 0 , counter * sizeof (long) , NGLOBAL , P2INT ); 177773Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 178773Speter putop( P2ASG P2PLUS , P2INT ); 179773Speter putdot( filename , line ); 180773Speter # endif PC 181773Speter } 182773Speter 183773Speter putline() 184773Speter { 185773Speter 186773Speter # ifdef OBJ 187773Speter if (opt('p') != 0) 1883079Smckusic put(2, O_LINO, line); 1895654Slinton 1905654Slinton /* 1915654Slinton * put out line number information for pdx 1925654Slinton */ 1935654Slinton lineno(line); 1945654Slinton 195773Speter # endif OBJ 196773Speter # ifdef PC 197773Speter static lastline; 198773Speter 199773Speter if ( line != lastline ) { 200773Speter stabline( line ); 201773Speter lastline = line; 202773Speter } 203773Speter if ( opt( 'p' ) ) { 204773Speter if ( opt('t') ) { 205773Speter putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 206773Speter , "_LINO" ); 207773Speter putop( P2UNARY P2CALL , P2INT ); 208773Speter putdot( filename , line ); 209773Speter } else { 2103835Speter putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 211773Speter putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 212773Speter putop( P2ASG P2PLUS , P2INT ); 213773Speter putdot( filename , line ); 214773Speter } 215773Speter } 216773Speter # endif PC 217773Speter } 218773Speter 219773Speter /* 220773Speter * With varlist do stat 221773Speter * 222773Speter * With statement requires an extra word 223773Speter * in automatic storage for each level of withing. 224773Speter * These indirect pointers are initialized here, and 225773Speter * the scoping effect of the with statement occurs 226773Speter * because lookup examines the field names of the records 227773Speter * associated with the WITHPTRs on the withlist. 228773Speter */ 229773Speter withop(s) 230773Speter int *s; 231773Speter { 232773Speter register *p; 233773Speter register struct nl *r; 2343835Speter struct nl *tempnlp; 235773Speter int *swl; 236773Speter 237773Speter putline(); 238773Speter swl = withlist; 239773Speter for (p = s[2]; p != NIL; p = p[2]) { 2403835Speter tempnlp = tmpalloc(sizeof(int *), INT_TYP, REGOK); 241773Speter # ifdef OBJ 2423835Speter put(2, O_LV | cbn <<8+INDX, tempnlp -> value[ NL_OFFS ] ); 243773Speter # endif OBJ 244773Speter # ifdef PC 2453835Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 2463835Speter tempnlp -> extra_flags , P2PTR|P2STRTY ); 247773Speter # endif PC 248773Speter r = lvalue(p[1], MOD , LREQ ); 249773Speter if (r == NIL) 250773Speter continue; 251773Speter if (r->class != RECORD) { 252773Speter error("Variable in with statement refers to %s, not to a record", nameof(r)); 253773Speter continue; 254773Speter } 2553835Speter r = defnl(0, WITHPTR, r, tempnlp -> value[ NL_OFFS ] ); 2563835Speter # ifdef PC 2573835Speter r -> extra_flags |= tempnlp -> extra_flags; 2583835Speter # endif PC 259773Speter r->nl_next = withlist; 260773Speter withlist = r; 261773Speter # ifdef OBJ 262773Speter put(1, PTR_AS); 263773Speter # endif OBJ 264773Speter # ifdef PC 265773Speter putop( P2ASSIGN , P2PTR|P2STRTY ); 266773Speter putdot( filename , line ); 267773Speter # endif PC 268773Speter } 269773Speter statement(s[3]); 270773Speter withlist = swl; 271773Speter } 272773Speter 273773Speter extern flagwas; 274773Speter /* 275773Speter * var := expr 276773Speter */ 277773Speter asgnop(r) 278773Speter int *r; 279773Speter { 280773Speter register struct nl *p; 281773Speter register *av; 282773Speter 283773Speter if (r == NIL) 284773Speter return (NIL); 285773Speter /* 286773Speter * Asgnop's only function is 287773Speter * to handle function variable 288773Speter * assignments. All other assignment 289773Speter * stuff is handled by asgnop1. 290773Speter * the if below checks for unqualified lefthandside: 291773Speter * necessary for fvars. 292773Speter */ 293773Speter av = r[2]; 294773Speter if (av != NIL && av[0] == T_VAR && av[3] == NIL) { 295773Speter p = lookup1(av[2]); 296773Speter if (p != NIL) 297773Speter p->nl_flags = flagwas; 298773Speter if (p != NIL && p->class == FVAR) { 299773Speter /* 300773Speter * Give asgnop1 the func 301773Speter * which is the chain of 302773Speter * the FVAR. 303773Speter */ 304773Speter p->nl_flags |= NUSED|NMOD; 305773Speter p = p->chain; 306773Speter if (p == NIL) { 307773Speter rvalue(r[3], NIL , RREQ ); 308773Speter return; 309773Speter } 310773Speter # ifdef OBJ 3113079Smckusic put(2, O_LV | bn << 8+INDX, (int)p->value[NL_OFFS]); 312773Speter if (isa(p->type, "i") && width(p->type) == 1) 313773Speter asgnop1(r, nl+T2INT); 314773Speter else 315773Speter asgnop1(r, p->type); 316773Speter # endif OBJ 317773Speter # ifdef PC 318773Speter /* 319773Speter * this should be the lvalue of the fvar, 320773Speter * but since the second pass knows to use 321773Speter * the address of the left operand of an 322773Speter * assignment, what i want here is an rvalue. 323773Speter * see note in funchdr about fvar allocation. 324773Speter */ 325773Speter p = p -> ptr[ NL_FVAR ]; 3263835Speter putRV( p -> symbol , bn , p -> value[ NL_OFFS ] , 3273835Speter p -> extra_flags , p2type( p -> type ) ); 328773Speter asgnop1( r , p -> type ); 329773Speter # endif PC 330773Speter return; 331773Speter } 332773Speter } 333773Speter asgnop1(r, NIL); 334773Speter } 335773Speter 336773Speter /* 337773Speter * Asgnop1 handles all assignments. 338773Speter * If p is not nil then we are assigning 339773Speter * to a function variable, otherwise 340773Speter * we look the variable up ourselves. 341773Speter */ 342773Speter struct nl * 343773Speter asgnop1(r, p) 344773Speter int *r; 345773Speter register struct nl *p; 346773Speter { 347773Speter register struct nl *p1; 3483079Smckusic int w; 349773Speter 350773Speter if (r == NIL) 351773Speter return (NIL); 352773Speter if (p == NIL) { 353773Speter # ifdef OBJ 354773Speter p = lvalue(r[2], MOD|ASGN|NOUSE , LREQ ); 3553079Smckusic w = width(p); 356773Speter # endif OBJ 357773Speter # ifdef PC 358773Speter /* 359773Speter * since the second pass knows that it should reference 360773Speter * the lefthandside of asignments, what i need here is 361773Speter * an rvalue. 362773Speter */ 363773Speter p = lvalue( r[2] , MOD|ASGN|NOUSE , RREQ ); 364773Speter # endif PC 365773Speter if ( p == NIL ) { 366773Speter rvalue( r[3] , NIL , RREQ ); 367773Speter return NIL; 368773Speter } 369773Speter } 370773Speter # ifdef OBJ 3713079Smckusic /* 3723079Smckusic * assigning to the return value, which is at least 3733079Smckusic * of width two since it resides on the stack 3743079Smckusic */ 3753079Smckusic else { 3763079Smckusic w = width(p); 3773079Smckusic if (w < 2) 3783079Smckusic w = 2; 3793079Smckusic } 380773Speter p1 = rvalue(r[3], p , RREQ ); 381773Speter # endif OBJ 382773Speter # ifdef PC 383773Speter /* 384773Speter * if this is a scalar assignment, 385773Speter * then i want to rvalue the righthandside. 386773Speter * if this is a structure assignment, 387773Speter * then i want an lvalue to the righthandside. 388773Speter * that's what the intermediate form sez. 389773Speter */ 390773Speter switch ( classify( p ) ) { 391773Speter case TINT: 392773Speter case TCHAR: 393773Speter case TBOOL: 394773Speter case TSCAL: 395773Speter precheck( p , "_RANG4" , "_RSNG4" ); 396773Speter case TDOUBLE: 397773Speter case TPTR: 398773Speter p1 = rvalue( r[3] , p , RREQ ); 399773Speter break; 400773Speter default: 401773Speter p1 = rvalue( r[3] , p , LREQ ); 402773Speter break; 403773Speter } 404773Speter # endif PC 405773Speter if (p1 == NIL) 406773Speter return (NIL); 407773Speter if (incompat(p1, p, r[3])) { 408773Speter cerror("Type of expression clashed with type of variable in assignment"); 409773Speter return (NIL); 410773Speter } 411*8758Speter # ifdef OBJ 412*8758Speter switch (classify(p)) { 413*8758Speter case TINT: 414*8758Speter case TBOOL: 415*8758Speter case TCHAR: 416*8758Speter case TSCAL: 417773Speter rangechk(p, p1); 418*8758Speter gen(O_AS2, O_AS2, w, width(p1)); 419*8758Speter break; 420*8758Speter case TDOUBLE: 421*8758Speter case TPTR: 422*8758Speter gen(O_AS2, O_AS2, w, width(p1)); 423*8758Speter break; 424*8758Speter default: 425*8758Speter put(2, O_AS, w); 426*8758Speter break; 427*8758Speter } 428*8758Speter # endif OBJ 429*8758Speter # ifdef PC 430*8758Speter switch (classify(p)) { 431*8758Speter case TINT: 432*8758Speter case TBOOL: 433*8758Speter case TCHAR: 434*8758Speter case TSCAL: 435773Speter postcheck( p ); 436773Speter putop( P2ASSIGN , p2type( p ) ); 437773Speter putdot( filename , line ); 438*8758Speter break; 439*8758Speter case TPTR: 440*8758Speter putop( P2ASSIGN , p2type( p ) ); 441*8758Speter putdot( filename , line ); 442*8758Speter break; 443*8758Speter case TDOUBLE: 444*8758Speter if (isnta(p1,"d")) { 445*8758Speter putop( P2SCONV , P2DOUBLE ); 446*8758Speter } 447*8758Speter putop( P2ASSIGN , p2type( p ) ); 448*8758Speter putdot( filename , line ); 449*8758Speter break; 450*8758Speter default: 451773Speter putstrop( P2STASG , p2type( p ) 452773Speter , lwidth( p ) , align( p ) ); 453773Speter putdot( filename , line ); 454*8758Speter break; 455*8758Speter } 456*8758Speter # 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