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