1 /* Copyright (c) 1979 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)stat.c 1.5 06/01/81"; 4 5 #include "whoami.h" 6 #include "0.h" 7 #include "tree.h" 8 #include "objfmt.h" 9 #ifdef PC 10 # include "pcops.h" 11 # include "pc.h" 12 #endif PC 13 14 int cntstat; 15 short cnts = 3; 16 #include "opcode.h" 17 18 /* 19 * Statement list 20 */ 21 statlist(r) 22 int *r; 23 { 24 register *sl; 25 26 for (sl=r; sl != NIL; sl=sl[2]) 27 statement(sl[1]); 28 } 29 30 /* 31 * Statement 32 */ 33 statement(r) 34 int *r; 35 { 36 register *s; 37 register struct nl *snlp; 38 struct tmps soffset; 39 40 s = r; 41 snlp = nlp; 42 soffset = sizes[cbn].curtmps; 43 top: 44 if (cntstat) { 45 cntstat = 0; 46 putcnt(); 47 } 48 if (s == NIL) 49 return; 50 line = s[1]; 51 if (s[0] == T_LABEL) { 52 labeled(s[2]); 53 s = s[3]; 54 noreach = 0; 55 cntstat = 1; 56 goto top; 57 } 58 if (noreach) { 59 noreach = 0; 60 warning(); 61 error("Unreachable statement"); 62 } 63 switch (s[0]) { 64 case T_PCALL: 65 putline(); 66 # ifdef OBJ 67 proc(s); 68 # endif OBJ 69 # ifdef PC 70 pcproc( s ); 71 # endif PC 72 break; 73 case T_ASGN: 74 putline(); 75 asgnop(s); 76 break; 77 case T_GOTO: 78 putline(); 79 gotoop(s[2]); 80 noreach = 1; 81 cntstat = 1; 82 break; 83 default: 84 level++; 85 switch (s[0]) { 86 default: 87 panic("stat"); 88 case T_IF: 89 case T_IFEL: 90 ifop(s); 91 break; 92 case T_WHILE: 93 whilop(s); 94 noreach = 0; 95 break; 96 case T_REPEAT: 97 repop(s); 98 break; 99 case T_FORU: 100 case T_FORD: 101 forop(s); 102 noreach = 0; 103 break; 104 case T_BLOCK: 105 statlist(s[2]); 106 break; 107 case T_CASE: 108 putline(); 109 # ifdef OBJ 110 caseop(s); 111 # endif OBJ 112 # ifdef PC 113 pccaseop( s ); 114 # endif PC 115 break; 116 case T_WITH: 117 withop(s); 118 break; 119 case T_ASRT: 120 putline(); 121 asrtop(s); 122 break; 123 } 124 --level; 125 if (gotos[cbn]) 126 ungoto(); 127 break; 128 } 129 /* 130 * Free the temporary name list entries defined in 131 * expressions, e.g. STRs, and WITHPTRs from withs. 132 */ 133 nlfree(snlp); 134 /* 135 * free any temporaries allocated for this statement 136 * these come from strings and sets. 137 */ 138 tmpfree(&soffset); 139 } 140 141 ungoto() 142 { 143 register struct nl *p; 144 145 for (p = gotos[cbn]; p != NIL; p = p->chain) 146 if ((p->nl_flags & NFORWD) != 0) { 147 if (p->value[NL_GOLEV] != NOTYET) 148 if (p->value[NL_GOLEV] > level) 149 p->value[NL_GOLEV] = level; 150 } else 151 if (p->value[NL_GOLEV] != DEAD) 152 if (p->value[NL_GOLEV] > level) 153 p->value[NL_GOLEV] = DEAD; 154 } 155 156 putcnt() 157 { 158 159 if (monflg == 0) { 160 return; 161 } 162 inccnt( getcnt() ); 163 } 164 165 int 166 getcnt() 167 { 168 169 return ++cnts; 170 } 171 172 inccnt( counter ) 173 int counter; 174 { 175 176 # ifdef OBJ 177 put(2, O_COUNT, counter ); 178 # endif OBJ 179 # ifdef PC 180 putRV( PCPCOUNT , 0 , counter * sizeof (long) , NGLOBAL , P2INT ); 181 putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 182 putop( P2ASG P2PLUS , P2INT ); 183 putdot( filename , line ); 184 # endif PC 185 } 186 187 putline() 188 { 189 190 # ifdef OBJ 191 if (opt('p') != 0) 192 put(2, O_LINO, line); 193 # endif OBJ 194 # ifdef PC 195 static lastline; 196 197 if ( line != lastline ) { 198 stabline( line ); 199 lastline = line; 200 } 201 if ( opt( 'p' ) ) { 202 if ( opt('t') ) { 203 putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 204 , "_LINO" ); 205 putop( P2UNARY P2CALL , P2INT ); 206 putdot( filename , line ); 207 } else { 208 putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 209 putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 210 putop( P2ASG P2PLUS , P2INT ); 211 putdot( filename , line ); 212 } 213 } 214 # endif PC 215 } 216 217 /* 218 * With varlist do stat 219 * 220 * With statement requires an extra word 221 * in automatic storage for each level of withing. 222 * These indirect pointers are initialized here, and 223 * the scoping effect of the with statement occurs 224 * because lookup examines the field names of the records 225 * associated with the WITHPTRs on the withlist. 226 */ 227 withop(s) 228 int *s; 229 { 230 register *p; 231 register struct nl *r; 232 struct nl *tempnlp; 233 int *swl; 234 235 putline(); 236 swl = withlist; 237 for (p = s[2]; p != NIL; p = p[2]) { 238 tempnlp = tmpalloc(sizeof(int *), INT_TYP, REGOK); 239 # ifdef OBJ 240 put(2, O_LV | cbn <<8+INDX, tempnlp -> value[ NL_OFFS ] ); 241 # endif OBJ 242 # ifdef PC 243 putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 244 tempnlp -> extra_flags , P2PTR|P2STRTY ); 245 # endif PC 246 r = lvalue(p[1], MOD , LREQ ); 247 if (r == NIL) 248 continue; 249 if (r->class != RECORD) { 250 error("Variable in with statement refers to %s, not to a record", nameof(r)); 251 continue; 252 } 253 r = defnl(0, WITHPTR, r, tempnlp -> value[ NL_OFFS ] ); 254 # ifdef PC 255 r -> extra_flags |= tempnlp -> extra_flags; 256 # endif PC 257 r->nl_next = withlist; 258 withlist = r; 259 # ifdef OBJ 260 put(1, PTR_AS); 261 # endif OBJ 262 # ifdef PC 263 putop( P2ASSIGN , P2PTR|P2STRTY ); 264 putdot( filename , line ); 265 # endif PC 266 } 267 statement(s[3]); 268 withlist = swl; 269 } 270 271 extern flagwas; 272 /* 273 * var := expr 274 */ 275 asgnop(r) 276 int *r; 277 { 278 register struct nl *p; 279 register *av; 280 281 if (r == NIL) 282 return (NIL); 283 /* 284 * Asgnop's only function is 285 * to handle function variable 286 * assignments. All other assignment 287 * stuff is handled by asgnop1. 288 * the if below checks for unqualified lefthandside: 289 * necessary for fvars. 290 */ 291 av = r[2]; 292 if (av != NIL && av[0] == T_VAR && av[3] == NIL) { 293 p = lookup1(av[2]); 294 if (p != NIL) 295 p->nl_flags = flagwas; 296 if (p != NIL && p->class == FVAR) { 297 /* 298 * Give asgnop1 the func 299 * which is the chain of 300 * the FVAR. 301 */ 302 p->nl_flags |= NUSED|NMOD; 303 p = p->chain; 304 if (p == NIL) { 305 rvalue(r[3], NIL , RREQ ); 306 return; 307 } 308 # ifdef OBJ 309 put(2, O_LV | bn << 8+INDX, (int)p->value[NL_OFFS]); 310 if (isa(p->type, "i") && width(p->type) == 1) 311 asgnop1(r, nl+T2INT); 312 else 313 asgnop1(r, p->type); 314 # endif OBJ 315 # ifdef PC 316 /* 317 * this should be the lvalue of the fvar, 318 * but since the second pass knows to use 319 * the address of the left operand of an 320 * assignment, what i want here is an rvalue. 321 * see note in funchdr about fvar allocation. 322 */ 323 p = p -> ptr[ NL_FVAR ]; 324 putRV( p -> symbol , bn , p -> value[ NL_OFFS ] , 325 p -> extra_flags , p2type( p -> type ) ); 326 asgnop1( r , p -> type ); 327 # endif PC 328 return; 329 } 330 } 331 asgnop1(r, NIL); 332 } 333 334 /* 335 * Asgnop1 handles all assignments. 336 * If p is not nil then we are assigning 337 * to a function variable, otherwise 338 * we look the variable up ourselves. 339 */ 340 struct nl * 341 asgnop1(r, p) 342 int *r; 343 register struct nl *p; 344 { 345 register struct nl *p1; 346 int w; 347 348 if (r == NIL) 349 return (NIL); 350 if (p == NIL) { 351 # ifdef OBJ 352 p = lvalue(r[2], MOD|ASGN|NOUSE , LREQ ); 353 w = width(p); 354 # endif OBJ 355 # ifdef PC 356 /* 357 * since the second pass knows that it should reference 358 * the lefthandside of asignments, what i need here is 359 * an rvalue. 360 */ 361 p = lvalue( r[2] , MOD|ASGN|NOUSE , RREQ ); 362 # endif PC 363 if ( p == NIL ) { 364 rvalue( r[3] , NIL , RREQ ); 365 return NIL; 366 } 367 } 368 # ifdef OBJ 369 /* 370 * assigning to the return value, which is at least 371 * of width two since it resides on the stack 372 */ 373 else { 374 w = width(p); 375 if (w < 2) 376 w = 2; 377 } 378 p1 = rvalue(r[3], p , RREQ ); 379 # endif OBJ 380 # ifdef PC 381 /* 382 * if this is a scalar assignment, 383 * then i want to rvalue the righthandside. 384 * if this is a structure assignment, 385 * then i want an lvalue to the righthandside. 386 * that's what the intermediate form sez. 387 */ 388 switch ( classify( p ) ) { 389 case TINT: 390 case TCHAR: 391 case TBOOL: 392 case TSCAL: 393 precheck( p , "_RANG4" , "_RSNG4" ); 394 case TDOUBLE: 395 case TPTR: 396 p1 = rvalue( r[3] , p , RREQ ); 397 break; 398 default: 399 p1 = rvalue( r[3] , p , LREQ ); 400 break; 401 } 402 # endif PC 403 if (p1 == NIL) 404 return (NIL); 405 if (incompat(p1, p, r[3])) { 406 cerror("Type of expression clashed with type of variable in assignment"); 407 return (NIL); 408 } 409 switch (classify(p)) { 410 case TINT: 411 case TBOOL: 412 case TCHAR: 413 case TSCAL: 414 # ifdef OBJ 415 rangechk(p, p1); 416 # endif OBJ 417 # ifdef PC 418 postcheck( p ); 419 # endif PC 420 case TDOUBLE: 421 case TPTR: 422 # ifdef OBJ 423 gen(O_AS2, O_AS2, w, width(p1)); 424 # endif OBJ 425 # ifdef PC 426 putop( P2ASSIGN , p2type( p ) ); 427 putdot( filename , line ); 428 # endif PC 429 break; 430 default: 431 # ifdef OBJ 432 put(2, O_AS, w); 433 # endif OBJ 434 # ifdef PC 435 putstrop( P2STASG , p2type( p ) 436 , lwidth( p ) , align( p ) ); 437 putdot( filename , line ); 438 # endif PC 439 } 440 return (p); /* Used by for statement */ 441 } 442 443 /* 444 * if expr then stat [ else stat ] 445 */ 446 ifop(r) 447 int *r; 448 { 449 register struct nl *p; 450 register l1, l2; /* l1 is start of else, l2 is end of else */ 451 int goc; 452 bool nr; 453 454 goc = gocnt; 455 if (r == NIL) 456 return; 457 putline(); 458 p = rvalue(r[2], NIL , RREQ ); 459 if (p == NIL) { 460 statement(r[3]); 461 noreach = 0; 462 statement(r[4]); 463 noreach = 0; 464 return; 465 } 466 if (isnta(p, "b")) { 467 error("Type of expression in if statement must be Boolean, not %s", nameof(p)); 468 statement(r[3]); 469 noreach = 0; 470 statement(r[4]); 471 noreach = 0; 472 return; 473 } 474 # ifdef OBJ 475 l1 = put(2, O_IF, getlab()); 476 # endif OBJ 477 # ifdef PC 478 l1 = getlab(); 479 putleaf( P2ICON , l1 , 0 , P2INT , 0 ); 480 putop( P2CBRANCH , P2INT ); 481 putdot( filename , line ); 482 # endif PC 483 putcnt(); 484 statement(r[3]); 485 nr = noreach; 486 if (r[4] != NIL) { 487 /* 488 * else stat 489 */ 490 --level; 491 ungoto(); 492 ++level; 493 # ifdef OBJ 494 l2 = put(2, O_TRA, getlab()); 495 # endif OBJ 496 # ifdef PC 497 l2 = getlab(); 498 putjbr( l2 ); 499 # endif PC 500 patch(l1); 501 noreach = 0; 502 statement(r[4]); 503 noreach = (noreach && nr); 504 l1 = l2; 505 } else 506 noreach = 0; 507 patch(l1); 508 if (goc != gocnt) 509 putcnt(); 510 } 511 512 /* 513 * while expr do stat 514 */ 515 whilop(r) 516 int *r; 517 { 518 register struct nl *p; 519 register l1, l2; 520 int goc; 521 522 goc = gocnt; 523 if (r == NIL) 524 return; 525 putlab(l1 = getlab()); 526 putline(); 527 p = rvalue(r[2], NIL , RREQ ); 528 if (p == NIL) { 529 statement(r[3]); 530 noreach = 0; 531 return; 532 } 533 if (isnta(p, "b")) { 534 error("Type of expression in while statement must be Boolean, not %s", nameof(p)); 535 statement(r[3]); 536 noreach = 0; 537 return; 538 } 539 l2 = getlab(); 540 # ifdef OBJ 541 put(2, O_IF, l2); 542 # endif OBJ 543 # ifdef PC 544 putleaf( P2ICON , l2 , 0 , P2INT , 0 ); 545 putop( P2CBRANCH , P2INT ); 546 putdot( filename , line ); 547 # endif PC 548 putcnt(); 549 statement(r[3]); 550 # ifdef OBJ 551 put(2, O_TRA, l1); 552 # endif OBJ 553 # ifdef PC 554 putjbr( l1 ); 555 # endif PC 556 patch(l2); 557 if (goc != gocnt) 558 putcnt(); 559 } 560 561 /* 562 * repeat stat* until expr 563 */ 564 repop(r) 565 int *r; 566 { 567 register struct nl *p; 568 register l; 569 int goc; 570 571 goc = gocnt; 572 if (r == NIL) 573 return; 574 l = putlab(getlab()); 575 putcnt(); 576 statlist(r[2]); 577 line = r[1]; 578 p = rvalue(r[3], NIL , RREQ ); 579 if (p == NIL) 580 return; 581 if (isnta(p,"b")) { 582 error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p)); 583 return; 584 } 585 # ifdef OBJ 586 put(2, O_IF, l); 587 # endif OBJ 588 # ifdef PC 589 putleaf( P2ICON , l , 0 , P2INT , 0 ); 590 putop( P2CBRANCH , P2INT ); 591 putdot( filename , line ); 592 # endif PC 593 if (goc != gocnt) 594 putcnt(); 595 } 596 597 /* 598 * assert expr 599 */ 600 asrtop(r) 601 register int *r; 602 { 603 register struct nl *q; 604 605 if (opt('s')) { 606 standard(); 607 error("Assert statement is non-standard"); 608 } 609 if (!opt('t')) 610 return; 611 r = r[2]; 612 # ifdef OBJ 613 q = rvalue((int *) r, NLNIL , RREQ ); 614 # endif OBJ 615 # ifdef PC 616 putleaf( P2ICON , 0 , 0 617 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ASRT" ); 618 q = stkrval( r , NLNIL , RREQ ); 619 # endif PC 620 if (q == NIL) 621 return; 622 if (isnta(q, "b")) 623 error("Assert expression must be Boolean, not %ss", nameof(q)); 624 # ifdef OBJ 625 put(1, O_ASRT); 626 # endif OBJ 627 # ifdef PC 628 putop( P2CALL , P2INT ); 629 putdot( filename , line ); 630 # endif PC 631 } 632