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