1758Speter /* Copyright (c) 1979 Regents of the University of California */ 2758Speter 315932Smckusick #ifndef lint 4*15967Smckusick static char sccsid[] = "@(#)lval.c 1.12 02/08/84"; 515932Smckusick #endif 6758Speter 7758Speter #include "whoami.h" 8758Speter #include "0.h" 9758Speter #include "tree.h" 10758Speter #include "opcode.h" 11758Speter #include "objfmt.h" 1215932Smckusick #include "tree_ty.h" 13758Speter #ifdef PC 14758Speter # include "pc.h" 15758Speter # include "pcops.h" 16758Speter #endif PC 17758Speter 18758Speter extern int flagwas; 19758Speter /* 20758Speter * Lvalue computes the address 21758Speter * of a qualified name and 22758Speter * leaves it on the stack. 23758Speter * for pc, it can be asked for either an lvalue or an rvalue. 24758Speter * the semantics are the same, only the code is different. 25758Speter */ 2615932Smckusick /*ARGSUSED*/ 27758Speter struct nl * 2815932Smckusick lvalue(var, modflag , required ) 2915932Smckusick struct tnode *var; 3015932Smckusick int modflag; 31758Speter int required; 32758Speter { 3315932Smckusick #ifdef OBJ 34758Speter register struct nl *p; 35758Speter struct nl *firstp, *lastp; 3615932Smckusick register struct tnode *c, *co; 37*15967Smckusick int f, o, s; 38758Speter /* 39758Speter * Note that the local optimizations 40758Speter * done here for offsets would more 41758Speter * appropriately be done in put. 42758Speter */ 4315932Smckusick struct tnode tr; /* T_FIELD */ 4415932Smckusick struct tnode *tr_ptr; 4515932Smckusick struct tnode l_node; 4615932Smckusick #endif 47758Speter 4815932Smckusick if (var == TR_NIL) { 4915932Smckusick return (NLNIL); 50758Speter } 5115932Smckusick if (nowexp(var)) { 5215932Smckusick return (NLNIL); 53758Speter } 5415932Smckusick if (var->tag != T_VAR) { 55758Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 5615932Smckusick return (NLNIL); 57758Speter } 58758Speter # ifdef PC 59758Speter /* 60758Speter * pc requires a whole different control flow 61758Speter */ 6215932Smckusick return pclvalue( var , modflag , required ); 63758Speter # endif PC 642122Smckusic # ifdef OBJ 652122Smckusic /* 662122Smckusic * pi uses the rest of the function 672122Smckusic */ 6815932Smckusick firstp = p = lookup(var->var_node.cptr); 6915932Smckusick if (p == NLNIL) { 7015932Smckusick return (NLNIL); 71758Speter } 7215932Smckusick c = var->var_node.qual; 73758Speter if ((modflag & NOUSE) && !lptr(c)) { 74758Speter p->nl_flags = flagwas; 75758Speter } 76758Speter if (modflag & MOD) { 77758Speter p->nl_flags |= NMOD; 78758Speter } 79758Speter /* 80758Speter * Only possibilities for p->class here 81758Speter * are the named classes, i.e. CONST, TYPE 82758Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 83758Speter */ 8415932Smckusick tr_ptr = &l_node; 85758Speter switch (p->class) { 86758Speter case WITHPTR: 87758Speter /* 88758Speter * Construct the tree implied by 89758Speter * the with statement 90758Speter */ 9115932Smckusick l_node.tag = T_LISTPP; 9215932Smckusick 9315932Smckusick /* the cast has got to go but until the node is figured 9415932Smckusick out it stays */ 9515932Smckusick 9615932Smckusick tr_ptr->list_node.list = (&tr); 9715932Smckusick tr_ptr->list_node.next = var->var_node.qual; 9815932Smckusick tr.tag = T_FIELD; 9915932Smckusick tr.field_node.id_ptr = var->var_node.cptr; 10015932Smckusick c = tr_ptr; /* c is a ptr to a tnode */ 101758Speter # ifdef PTREE 102758Speter /* 10315932Smckusick * mung var->fields to say which field this T_VAR is 104758Speter * for VarCopy 105758Speter */ 10615932Smckusick 10715932Smckusick /* problem! reclook returns struct nl* */ 10815932Smckusick 10915932Smckusick var->var_node.fields = reclook( p -> type , 11015932Smckusick var->var_node.line_no ); 111758Speter # endif 112758Speter /* and fall through */ 113758Speter case REF: 114758Speter /* 115758Speter * Obtain the indirect word 116758Speter * of the WITHPTR or REF 117758Speter * as the base of our lvalue 118758Speter */ 11915932Smckusick (void) put(2, PTR_RV | bn << 8+INDX , (int)p->value[0] ); 120758Speter f = 0; /* have an lv on stack */ 121758Speter o = 0; 122758Speter break; 123758Speter case VAR: 124*15967Smckusick if (p->type->class != CRANGE) { 125*15967Smckusick f = 1; /* no lv on stack yet */ 126*15967Smckusick o = p->value[0]; 127*15967Smckusick } else { 128*15967Smckusick error("Conformant array bound %s found where variable required", p->symbol); 129*15967Smckusick return(NLNIL); 130*15967Smckusick } 131758Speter break; 132758Speter default: 133758Speter error("%s %s found where variable required", classes[p->class], p->symbol); 13415932Smckusick return (NLNIL); 135758Speter } 136758Speter /* 137758Speter * Loop and handle each 138758Speter * qualification on the name 139758Speter */ 14015932Smckusick if (c == TR_NIL && (modflag&ASGN) && ( p->value[NL_FORV] & FORVAR ) ) { 141758Speter error("Can't modify the for variable %s in the range of the loop", p->symbol); 14215932Smckusick return (NLNIL); 143758Speter } 144*15967Smckusick s = 0; /* subscripts seen */ 14515932Smckusick for (; c != TR_NIL; c = c->list_node.next) { 14615932Smckusick co = c->list_node.list; /* co is a ptr to a tnode */ 14715932Smckusick if (co == TR_NIL) { 14815932Smckusick return (NLNIL); 149758Speter } 150758Speter lastp = p; 151758Speter p = p->type; 15215932Smckusick if (p == NLNIL) { 15315932Smckusick return (NLNIL); 154758Speter } 155*15967Smckusick /* 156*15967Smckusick * If we haven't seen enough subscripts, and the next 157*15967Smckusick * qualification isn't array reference, then it's an error. 158*15967Smckusick */ 159*15967Smckusick if (s && co->tag != T_ARY) { 160*15967Smckusick error("Too few subscripts (%d given, %d required)", 161*15967Smckusick s, p->value[0]); 162*15967Smckusick } 16315932Smckusick switch (co->tag) { 164758Speter case T_PTR: 165758Speter /* 166758Speter * Pointer qualification. 167758Speter */ 168758Speter lastp->nl_flags |= NUSED; 169758Speter if (p->class != PTR && p->class != FILET) { 170758Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 171758Speter goto bad; 172758Speter } 173758Speter if (f) { 1742071Smckusic if (p->class == FILET && bn != 0) 17515932Smckusick (void) put(2, O_LV | bn <<8+INDX , o ); 1762071Smckusic else 1772071Smckusic /* 1782071Smckusic * this is the indirection from 1792071Smckusic * the address of the pointer 1802071Smckusic * to the pointer itself. 1812071Smckusic * kirk sez: 1822071Smckusic * fnil doesn't want this. 1832071Smckusic * and does it itself for files 1842071Smckusic * since only it knows where the 1852071Smckusic * actual window is. 1862071Smckusic * but i have to do this for 1872071Smckusic * regular pointers. 1882071Smckusic * This is further complicated by 1892071Smckusic * the fact that global variables 1902071Smckusic * are referenced through pointers 1912071Smckusic * on the stack. Thus an RV on a 1922071Smckusic * global variable is the same as 1932071Smckusic * an LV of a non-global one ?!? 1942071Smckusic */ 19515932Smckusick (void) put(2, PTR_RV | bn <<8+INDX , o ); 196758Speter } else { 197758Speter if (o) { 19815932Smckusick (void) put(2, O_OFF, o); 199758Speter } 2002104Smckusic if (p->class != FILET || bn == 0) 20115932Smckusick (void) put(1, PTR_IND); 202758Speter } 203758Speter /* 204758Speter * Pointer cannot be 205758Speter * nil and file cannot 206758Speter * be at end-of-file. 207758Speter */ 20815932Smckusick (void) put(1, p->class == FILET ? O_FNIL : O_NIL); 209758Speter f = o = 0; 210758Speter continue; 211758Speter case T_ARGL: 212758Speter if (p->class != ARRAY) { 213758Speter if (lastp == firstp) { 21415932Smckusick error("%s is a %s, not a function", var->var_node.cptr, classes[firstp->class]); 215758Speter } else { 216758Speter error("Illegal function qualificiation"); 217758Speter } 21815932Smckusick return (NLNIL); 219758Speter } 220758Speter recovered(); 221758Speter error("Pascal uses [] for subscripting, not ()"); 222758Speter case T_ARY: 223758Speter if (p->class != ARRAY) { 224758Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 225758Speter goto bad; 226758Speter } 227758Speter if (f) { 2282071Smckusic if (bn == 0) 2292071Smckusic /* 2302071Smckusic * global variables are 2312071Smckusic * referenced through pointers 2322071Smckusic * on the stack 2332071Smckusic */ 23415932Smckusick (void) put(2, PTR_RV | bn<<8+INDX, o); 2352071Smckusic else 23615932Smckusick (void) put(2, O_LV | bn<<8+INDX, o); 237758Speter } else { 238758Speter if (o) { 23915932Smckusick (void) put(2, O_OFF, o); 240758Speter } 241758Speter } 242*15967Smckusick switch(s = arycod(p,co->ary_node.expr_list,s)) { 243*15967Smckusick /* 244*15967Smckusick * This is the number of subscripts seen 245*15967Smckusick */ 246758Speter case 0: 24715932Smckusick return (NLNIL); 248758Speter case -1: 249758Speter goto bad; 250758Speter } 251*15967Smckusick if (s == p->value[0]) { 252*15967Smckusick s = 0; 253*15967Smckusick } else { 254*15967Smckusick p = lastp; 255*15967Smckusick } 256758Speter f = o = 0; 257758Speter continue; 258758Speter case T_FIELD: 259758Speter /* 260758Speter * Field names are just 261758Speter * an offset with some 262758Speter * semantic checking. 263758Speter */ 264758Speter if (p->class != RECORD) { 265758Speter error(". allowed only on records, not on %ss", nameof(p)); 266758Speter goto bad; 267758Speter } 26815932Smckusick /* must define the field node!! */ 26915932Smckusick if (co->field_node.id_ptr == NIL) { 27015932Smckusick return (NLNIL); 271758Speter } 27215932Smckusick p = reclook(p, co->field_node.id_ptr); 27315932Smckusick if (p == NLNIL) { 27415932Smckusick error("%s is not a field in this record", co->field_node.id_ptr); 275758Speter goto bad; 276758Speter } 277758Speter # ifdef PTREE 278758Speter /* 279758Speter * mung co[3] to indicate which field 280758Speter * this is for SelCopy 281758Speter */ 28215932Smckusick co->field_node.nl_entry = p; 283758Speter # endif 284758Speter if (modflag & MOD) { 285758Speter p->nl_flags |= NMOD; 286758Speter } 28715932Smckusick if ((modflag & NOUSE) == 0 || 28815932Smckusick lptr(c->list_node.next)) { 28915932Smckusick /* figure out what kind of node c is !! */ 290758Speter p->nl_flags |= NUSED; 291758Speter } 292758Speter o += p->value[0]; 293758Speter continue; 294758Speter default: 295758Speter panic("lval2"); 296758Speter } 297758Speter } 298*15967Smckusick if (s) { 299*15967Smckusick error("Too few subscripts (%d given, %d required)", 300*15967Smckusick s, p->type->value[0]); 301*15967Smckusick } 302758Speter if (f) { 3032071Smckusic if (bn == 0) 3042071Smckusic /* 3052071Smckusic * global variables are referenced through 3062071Smckusic * pointers on the stack 3072071Smckusic */ 30815932Smckusick (void) put(2, PTR_RV | bn<<8+INDX, o); 3092071Smckusic else 31015932Smckusick (void) put(2, O_LV | bn<<8+INDX, o); 311758Speter } else { 312758Speter if (o) { 31315932Smckusick (void) put(2, O_OFF, o); 314758Speter } 315758Speter } 316758Speter return (p->type); 317758Speter bad: 31815932Smckusick cerror("Error occurred on qualification of %s", var->var_node.cptr); 31915932Smckusick return (NLNIL); 3202122Smckusic # endif OBJ 321758Speter } 322758Speter 32315932Smckusick int lptr(c) 32415932Smckusick register struct tnode *c; 325758Speter { 32615932Smckusick register struct tnode *co; 327758Speter 32815932Smckusick for (; c != TR_NIL; c = c->list_node.next) { 32915932Smckusick co = c->list_node.list; 33015932Smckusick if (co == TR_NIL) { 331758Speter return (NIL); 332758Speter } 33315932Smckusick switch (co->tag) { 334758Speter 335758Speter case T_PTR: 336758Speter return (1); 337758Speter case T_ARGL: 338758Speter return (0); 339758Speter case T_ARY: 340758Speter case T_FIELD: 341758Speter continue; 342758Speter default: 343758Speter panic("lptr"); 344758Speter } 345758Speter } 346758Speter return (0); 347758Speter } 348758Speter 349758Speter /* 350758Speter * Arycod does the 351758Speter * code generation 352758Speter * for subscripting. 353*15967Smckusick * n is the number of 354*15967Smckusick * subscripts already seen 355*15967Smckusick * (CLN 09/13/83) 356758Speter */ 357*15967Smckusick int arycod(np, el, n) 358758Speter struct nl *np; 35915932Smckusick struct tnode *el; 360*15967Smckusick int n; 361758Speter { 362758Speter register struct nl *p, *ap; 3633890Smckusic long sub; 3643890Smckusic bool constsub; 36515932Smckusick extern bool constval(); 36615932Smckusick int i, d; /* v, v1; these aren't used */ 367758Speter int w; 368758Speter 369758Speter p = np; 37015932Smckusick if (el == TR_NIL) { 371758Speter return (0); 372758Speter } 373758Speter d = p->value[0]; 374*15967Smckusick for (i = 1; i <= n; i++) { 375*15967Smckusick p = p->chain; 376*15967Smckusick } 377758Speter /* 378758Speter * Check each subscript 379758Speter */ 380*15967Smckusick for (i = n+1; i <= d; i++) { 38115932Smckusick if (el == TR_NIL) { 382*15967Smckusick return (i-1); 383758Speter } 384758Speter p = p->chain; 385*15967Smckusick if ((p->class != CRANGE) && 386*15967Smckusick (constsub = constval(el->list_node.list))) { 3873890Smckusic ap = con.ctype; 3883890Smckusic sub = con.crval; 3893890Smckusic if (sub < p->range[0] || sub > p->range[1]) { 39015932Smckusick error("Subscript value of %D is out of range", (char *) sub); 391758Speter return (0); 3923890Smckusic } 3933890Smckusic sub -= p->range[0]; 3943890Smckusic } else { 3953890Smckusic # ifdef PC 3963890Smckusic precheck( p , "_SUBSC" , "_SUBSCZ" ); 3973890Smckusic # endif PC 39815932Smckusick ap = rvalue(el->list_node.list, NLNIL , RREQ ); 3993890Smckusic if (ap == NIL) { 4003890Smckusic return (0); 4013890Smckusic } 4023890Smckusic # ifdef PC 40310361Smckusick postcheck(p, ap); 40410361Smckusick sconv(p2type(ap),P2INT); 4053890Smckusic # endif PC 406758Speter } 40715932Smckusick if (incompat(ap, p->type, el->list_node.list)) { 408758Speter cerror("Array index type incompatible with declared index type"); 409758Speter if (d != 1) { 41015932Smckusick cerror("Error occurred on index number %d", (char *) i); 411758Speter } 412758Speter return (-1); 413758Speter } 414*15967Smckusick if (p->class == CRANGE) { 415*15967Smckusick constsub = 0; 416*15967Smckusick } else { 417*15967Smckusick w = aryconst(np, i); 418*15967Smckusick } 419758Speter # ifdef OBJ 4203890Smckusic if (constsub) { 4213890Smckusic sub *= w; 4223890Smckusic if (sub != 0) { 42315933Smckusick w = bytes(sub, sub); 42415932Smckusick (void) put(2, w <= 2 ? O_CON2 : O_CON4, sub); 42515932Smckusick (void) gen(NIL, T_ADD, sizeof(char *), w); 4263890Smckusic } 42715932Smckusick el = el->list_node.next; 4283890Smckusic continue; 4293890Smckusic } 430*15967Smckusick if (p->class == CRANGE) { 431*15967Smckusick putcbnds(p, 0); 432*15967Smckusick putcbnds(p, 1); 433*15967Smckusick putcbnds(p, 2); 434*15967Smckusick } else if (opt('t') == 0) { 435758Speter switch (w) { 436758Speter case 8: 437758Speter w = 6; 438758Speter case 4: 439758Speter case 2: 440758Speter case 1: 44115932Smckusick (void) put(2, (width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]); 44215932Smckusick el = el->list_node.next; 443758Speter continue; 444758Speter } 445758Speter } 446*15967Smckusick if (p->class == CRANGE) { 447*15967Smckusick if (width(p) == 4) { 448*15967Smckusick put(1, width(ap) != 4 ? O_VINX42 : O_VINX4); 449*15967Smckusick } else { 450*15967Smckusick put(1, width(ap) != 4 ? O_VINX2 : O_VINX24); 451*15967Smckusick } 452*15967Smckusick } else { 453*15967Smckusick put(4, width(ap) != 4 ? O_INX2 : O_INX4, w, 454*15967Smckusick (short)p->range[0], (short)(p->range[1])); 455*15967Smckusick } 45615932Smckusick el = el->list_node.next; 4573890Smckusic continue; 458758Speter # endif OBJ 459758Speter # ifdef PC 460758Speter /* 461758Speter * subtract off the lower bound 462758Speter */ 4633890Smckusic if (constsub) { 4643890Smckusic sub *= w; 4653890Smckusic if (sub != 0) { 46615932Smckusick putleaf( P2ICON , (int) sub , 0 , P2INT , (char *) 0 ); 4673890Smckusic putop(P2PLUS, ADDTYPE(p2type(np->type), P2PTR)); 4683890Smckusic } 46915932Smckusick el = el->list_node.next; 4703890Smckusic continue; 4713890Smckusic } 472*15967Smckusick if (p->class == CRANGE) { 473758Speter /* 474*15967Smckusick * if conformant array, subtract off lower bound 475758Speter */ 476*15967Smckusick ap = p->nptr[0]; 477*15967Smckusick putRV(ap->symbol, (ap->nl_block & 037), ap->value[0], 478*15967Smckusick ap->extra_flags, p2type( ap ) ); 479*15967Smckusick putop( P2MINUS, P2INT ); 480*15967Smckusick /* 481*15967Smckusick * and multiply by the width of the elements 482*15967Smckusick */ 483*15967Smckusick ap = p->nptr[2]; 484*15967Smckusick putRV( 0 , (ap->nl_block & 037), ap->value[0], 485*15967Smckusick ap->extra_flags, p2type( ap ) ); 486758Speter putop( P2MUL , P2INT ); 487*15967Smckusick } else { 488*15967Smckusick if ( p -> range[ 0 ] != 0 ) { 489*15967Smckusick putleaf( P2ICON , (int) p -> range[0] , 0 , P2INT , (char *) 0 ); 490*15967Smckusick putop( P2MINUS , P2INT ); 491*15967Smckusick } 492*15967Smckusick /* 493*15967Smckusick * multiply by the width of the elements 494*15967Smckusick */ 495*15967Smckusick if ( w != 1 ) { 496*15967Smckusick putleaf( P2ICON , w , 0 , P2INT , (char *) 0 ); 497*15967Smckusick putop( P2MUL , P2INT ); 498*15967Smckusick } 499758Speter } 500758Speter /* 501758Speter * and add it to the base address 502758Speter */ 503758Speter putop( P2PLUS , ADDTYPE( p2type( np -> type ) , P2PTR ) ); 50415932Smckusick el = el->list_node.next; 505758Speter # endif PC 506758Speter } 50715932Smckusick if (el != TR_NIL) { 508*15967Smckusick if (np->type->class != ARRAY) { 509758Speter do { 51015932Smckusick el = el->list_node.next; 511758Speter i++; 51215932Smckusick } while (el != TR_NIL); 51315932Smckusick error("Too many subscripts (%d given, %d required)", (char *) (i-1), (char *) d); 514758Speter return (-1); 515*15967Smckusick } else { 516*15967Smckusick return(arycod(np->type, el, d)); 517*15967Smckusick } 518758Speter } 519*15967Smckusick return (d); 520758Speter } 521*15967Smckusick 522*15967Smckusick #ifdef OBJ 523*15967Smckusick /* 524*15967Smckusick * Put out the conformant array bounds (lower bound, upper bound or width) 525*15967Smckusick * for conformant array type ctype. 526*15967Smckusick * The value of i determines which is being put 527*15967Smckusick * i = 0: lower bound, i=1: upper bound, i=2: width 528*15967Smckusick */ 529*15967Smckusick putcbnds(ctype, i) 530*15967Smckusick struct nl *ctype; 531*15967Smckusick int i; 532*15967Smckusick { 533*15967Smckusick switch(width(ctype->type)) { 534*15967Smckusick case 1: 535*15967Smckusick put(2, O_RV1 | (ctype->nl_block & 037) << 8+INDX, 536*15967Smckusick (int)ctype->nptr[i]->value[0]); 537*15967Smckusick break; 538*15967Smckusick case 2: 539*15967Smckusick put(2, O_RV2 | (ctype->nl_block & 037) << 8+INDX, 540*15967Smckusick (int)ctype->nptr[i]->value[0]); 541*15967Smckusick break; 542*15967Smckusick case 4: 543*15967Smckusick default: 544*15967Smckusick put(2, O_RV4 | (ctype->nl_block & 037) << 8+INDX, 545*15967Smckusick (int)ctype->nptr[i]->value[0]); 546*15967Smckusick } 547*15967Smckusick } 548*15967Smckusick #endif OBJ 549