1758Speter /* Copyright (c) 1979 Regents of the University of California */ 2758Speter 315932Smckusick #ifndef lint 4*15986Saoki static char sccsid[] = "@(#)lval.c 1.13 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; 3715967Smckusick 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: 12415967Smckusick if (p->type->class != CRANGE) { 12515967Smckusick f = 1; /* no lv on stack yet */ 12615967Smckusick o = p->value[0]; 12715967Smckusick } else { 12815967Smckusick error("Conformant array bound %s found where variable required", p->symbol); 12915967Smckusick return(NLNIL); 13015967Smckusick } 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 } 14415967Smckusick 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 } 15515967Smckusick /* 15615967Smckusick * If we haven't seen enough subscripts, and the next 15715967Smckusick * qualification isn't array reference, then it's an error. 15815967Smckusick */ 15915967Smckusick if (s && co->tag != T_ARY) { 16015967Smckusick error("Too few subscripts (%d given, %d required)", 16115967Smckusick s, p->value[0]); 16215967Smckusick } 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 } 24215967Smckusick switch(s = arycod(p,co->ary_node.expr_list,s)) { 24315967Smckusick /* 24415967Smckusick * This is the number of subscripts seen 24515967Smckusick */ 246758Speter case 0: 24715932Smckusick return (NLNIL); 248758Speter case -1: 249758Speter goto bad; 250758Speter } 25115967Smckusick if (s == p->value[0]) { 25215967Smckusick s = 0; 25315967Smckusick } else { 25415967Smckusick p = lastp; 25515967Smckusick } 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 } 29815967Smckusick if (s) { 29915967Smckusick error("Too few subscripts (%d given, %d required)", 30015967Smckusick s, p->type->value[0]); 301*15986Saoki return NLNIL; 30215967Smckusick } 303758Speter if (f) { 3042071Smckusic if (bn == 0) 3052071Smckusic /* 3062071Smckusic * global variables are referenced through 3072071Smckusic * pointers on the stack 3082071Smckusic */ 30915932Smckusick (void) put(2, PTR_RV | bn<<8+INDX, o); 3102071Smckusic else 31115932Smckusick (void) put(2, O_LV | bn<<8+INDX, o); 312758Speter } else { 313758Speter if (o) { 31415932Smckusick (void) put(2, O_OFF, o); 315758Speter } 316758Speter } 317758Speter return (p->type); 318758Speter bad: 31915932Smckusick cerror("Error occurred on qualification of %s", var->var_node.cptr); 32015932Smckusick return (NLNIL); 3212122Smckusic # endif OBJ 322758Speter } 323758Speter 32415932Smckusick int lptr(c) 32515932Smckusick register struct tnode *c; 326758Speter { 32715932Smckusick register struct tnode *co; 328758Speter 32915932Smckusick for (; c != TR_NIL; c = c->list_node.next) { 33015932Smckusick co = c->list_node.list; 33115932Smckusick if (co == TR_NIL) { 332758Speter return (NIL); 333758Speter } 33415932Smckusick switch (co->tag) { 335758Speter 336758Speter case T_PTR: 337758Speter return (1); 338758Speter case T_ARGL: 339758Speter return (0); 340758Speter case T_ARY: 341758Speter case T_FIELD: 342758Speter continue; 343758Speter default: 344758Speter panic("lptr"); 345758Speter } 346758Speter } 347758Speter return (0); 348758Speter } 349758Speter 350758Speter /* 351758Speter * Arycod does the 352758Speter * code generation 353758Speter * for subscripting. 35415967Smckusick * n is the number of 35515967Smckusick * subscripts already seen 35615967Smckusick * (CLN 09/13/83) 357758Speter */ 35815967Smckusick int arycod(np, el, n) 359758Speter struct nl *np; 36015932Smckusick struct tnode *el; 36115967Smckusick int n; 362758Speter { 363758Speter register struct nl *p, *ap; 3643890Smckusic long sub; 3653890Smckusic bool constsub; 36615932Smckusick extern bool constval(); 36715932Smckusick int i, d; /* v, v1; these aren't used */ 368758Speter int w; 369758Speter 370758Speter p = np; 37115932Smckusick if (el == TR_NIL) { 372758Speter return (0); 373758Speter } 374758Speter d = p->value[0]; 37515967Smckusick for (i = 1; i <= n; i++) { 37615967Smckusick p = p->chain; 37715967Smckusick } 378758Speter /* 379758Speter * Check each subscript 380758Speter */ 38115967Smckusick for (i = n+1; i <= d; i++) { 38215932Smckusick if (el == TR_NIL) { 38315967Smckusick return (i-1); 384758Speter } 385758Speter p = p->chain; 38615967Smckusick if ((p->class != CRANGE) && 38715967Smckusick (constsub = constval(el->list_node.list))) { 3883890Smckusic ap = con.ctype; 3893890Smckusic sub = con.crval; 3903890Smckusic if (sub < p->range[0] || sub > p->range[1]) { 39115932Smckusick error("Subscript value of %D is out of range", (char *) sub); 392758Speter return (0); 3933890Smckusic } 3943890Smckusic sub -= p->range[0]; 3953890Smckusic } else { 3963890Smckusic # ifdef PC 3973890Smckusic precheck( p , "_SUBSC" , "_SUBSCZ" ); 3983890Smckusic # endif PC 39915932Smckusick ap = rvalue(el->list_node.list, NLNIL , RREQ ); 4003890Smckusic if (ap == NIL) { 4013890Smckusic return (0); 4023890Smckusic } 4033890Smckusic # ifdef PC 40410361Smckusick postcheck(p, ap); 40510361Smckusick sconv(p2type(ap),P2INT); 4063890Smckusic # endif PC 407758Speter } 40815932Smckusick if (incompat(ap, p->type, el->list_node.list)) { 409758Speter cerror("Array index type incompatible with declared index type"); 410758Speter if (d != 1) { 41115932Smckusick cerror("Error occurred on index number %d", (char *) i); 412758Speter } 413758Speter return (-1); 414758Speter } 41515967Smckusick if (p->class == CRANGE) { 416*15986Saoki constsub = FALSE; 41715967Smckusick } else { 41815967Smckusick w = aryconst(np, i); 41915967Smckusick } 420758Speter # ifdef OBJ 4213890Smckusic if (constsub) { 4223890Smckusic sub *= w; 4233890Smckusic if (sub != 0) { 42415933Smckusick w = bytes(sub, sub); 42515932Smckusick (void) put(2, w <= 2 ? O_CON2 : O_CON4, sub); 42615932Smckusick (void) gen(NIL, T_ADD, sizeof(char *), w); 4273890Smckusic } 42815932Smckusick el = el->list_node.next; 4293890Smckusic continue; 4303890Smckusic } 43115967Smckusick if (p->class == CRANGE) { 43215967Smckusick putcbnds(p, 0); 43315967Smckusick putcbnds(p, 1); 43415967Smckusick putcbnds(p, 2); 43515967Smckusick } else if (opt('t') == 0) { 436758Speter switch (w) { 437758Speter case 8: 438758Speter w = 6; 439758Speter case 4: 440758Speter case 2: 441758Speter case 1: 44215932Smckusick (void) put(2, (width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]); 44315932Smckusick el = el->list_node.next; 444758Speter continue; 445758Speter } 446758Speter } 44715967Smckusick if (p->class == CRANGE) { 44815967Smckusick if (width(p) == 4) { 44915967Smckusick put(1, width(ap) != 4 ? O_VINX42 : O_VINX4); 45015967Smckusick } else { 45115967Smckusick put(1, width(ap) != 4 ? O_VINX2 : O_VINX24); 45215967Smckusick } 45315967Smckusick } else { 45415967Smckusick put(4, width(ap) != 4 ? O_INX2 : O_INX4, w, 45515967Smckusick (short)p->range[0], (short)(p->range[1])); 45615967Smckusick } 45715932Smckusick el = el->list_node.next; 4583890Smckusic continue; 459758Speter # endif OBJ 460758Speter # ifdef PC 461758Speter /* 462758Speter * subtract off the lower bound 463758Speter */ 4643890Smckusic if (constsub) { 4653890Smckusic sub *= w; 4663890Smckusic if (sub != 0) { 46715932Smckusick putleaf( P2ICON , (int) sub , 0 , P2INT , (char *) 0 ); 4683890Smckusic putop(P2PLUS, ADDTYPE(p2type(np->type), P2PTR)); 4693890Smckusic } 47015932Smckusick el = el->list_node.next; 4713890Smckusic continue; 4723890Smckusic } 47315967Smckusick if (p->class == CRANGE) { 474758Speter /* 47515967Smckusick * if conformant array, subtract off lower bound 476758Speter */ 47715967Smckusick ap = p->nptr[0]; 47815967Smckusick putRV(ap->symbol, (ap->nl_block & 037), ap->value[0], 47915967Smckusick ap->extra_flags, p2type( ap ) ); 48015967Smckusick putop( P2MINUS, P2INT ); 48115967Smckusick /* 48215967Smckusick * and multiply by the width of the elements 48315967Smckusick */ 48415967Smckusick ap = p->nptr[2]; 48515967Smckusick putRV( 0 , (ap->nl_block & 037), ap->value[0], 48615967Smckusick ap->extra_flags, p2type( ap ) ); 487758Speter putop( P2MUL , P2INT ); 48815967Smckusick } else { 48915967Smckusick if ( p -> range[ 0 ] != 0 ) { 49015967Smckusick putleaf( P2ICON , (int) p -> range[0] , 0 , P2INT , (char *) 0 ); 49115967Smckusick putop( P2MINUS , P2INT ); 49215967Smckusick } 49315967Smckusick /* 49415967Smckusick * multiply by the width of the elements 49515967Smckusick */ 49615967Smckusick if ( w != 1 ) { 49715967Smckusick putleaf( P2ICON , w , 0 , P2INT , (char *) 0 ); 49815967Smckusick putop( P2MUL , P2INT ); 49915967Smckusick } 500758Speter } 501758Speter /* 502758Speter * and add it to the base address 503758Speter */ 504758Speter putop( P2PLUS , ADDTYPE( p2type( np -> type ) , P2PTR ) ); 50515932Smckusick el = el->list_node.next; 506758Speter # endif PC 507758Speter } 50815932Smckusick if (el != TR_NIL) { 50915967Smckusick if (np->type->class != ARRAY) { 510758Speter do { 51115932Smckusick el = el->list_node.next; 512758Speter i++; 51315932Smckusick } while (el != TR_NIL); 51415932Smckusick error("Too many subscripts (%d given, %d required)", (char *) (i-1), (char *) d); 515758Speter return (-1); 51615967Smckusick } else { 51715967Smckusick return(arycod(np->type, el, d)); 51815967Smckusick } 519758Speter } 52015967Smckusick return (d); 521758Speter } 52215967Smckusick 52315967Smckusick #ifdef OBJ 52415967Smckusick /* 52515967Smckusick * Put out the conformant array bounds (lower bound, upper bound or width) 52615967Smckusick * for conformant array type ctype. 52715967Smckusick * The value of i determines which is being put 52815967Smckusick * i = 0: lower bound, i=1: upper bound, i=2: width 52915967Smckusick */ 53015967Smckusick putcbnds(ctype, i) 53115967Smckusick struct nl *ctype; 53215967Smckusick int i; 53315967Smckusick { 53415967Smckusick switch(width(ctype->type)) { 53515967Smckusick case 1: 53615967Smckusick put(2, O_RV1 | (ctype->nl_block & 037) << 8+INDX, 53715967Smckusick (int)ctype->nptr[i]->value[0]); 53815967Smckusick break; 53915967Smckusick case 2: 54015967Smckusick put(2, O_RV2 | (ctype->nl_block & 037) << 8+INDX, 54115967Smckusick (int)ctype->nptr[i]->value[0]); 54215967Smckusick break; 54315967Smckusick case 4: 54415967Smckusick default: 54515967Smckusick put(2, O_RV4 | (ctype->nl_block & 037) << 8+INDX, 54615967Smckusick (int)ctype->nptr[i]->value[0]); 54715967Smckusick } 54815967Smckusick } 54915967Smckusick #endif OBJ 550