1758Speter /* Copyright (c) 1979 Regents of the University of California */ 2758Speter 3*10361Smckusick static char sccsid[] = "@(#)lval.c 1.9 01/17/83"; 4758Speter 5758Speter #include "whoami.h" 6758Speter #include "0.h" 7758Speter #include "tree.h" 8758Speter #include "opcode.h" 9758Speter #include "objfmt.h" 10758Speter #ifdef PC 11758Speter # include "pc.h" 12758Speter # include "pcops.h" 13758Speter #endif PC 14758Speter 15758Speter extern int flagwas; 16758Speter /* 17758Speter * Lvalue computes the address 18758Speter * of a qualified name and 19758Speter * leaves it on the stack. 20758Speter * for pc, it can be asked for either an lvalue or an rvalue. 21758Speter * the semantics are the same, only the code is different. 22758Speter */ 23758Speter struct nl * 24758Speter lvalue(r, modflag , required ) 25758Speter int *r, modflag; 26758Speter int required; 27758Speter { 28758Speter register struct nl *p; 29758Speter struct nl *firstp, *lastp; 30758Speter register *c, *co; 31758Speter int f, o; 32758Speter /* 33758Speter * Note that the local optimizations 34758Speter * done here for offsets would more 35758Speter * appropriately be done in put. 36758Speter */ 37758Speter int tr[2], trp[3]; 38758Speter 39758Speter if (r == NIL) { 40758Speter return (NIL); 41758Speter } 42758Speter if (nowexp(r)) { 43758Speter return (NIL); 44758Speter } 45758Speter if (r[0] != T_VAR) { 46758Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 47758Speter return (NIL); 48758Speter } 49758Speter # ifdef PC 50758Speter /* 51758Speter * pc requires a whole different control flow 52758Speter */ 53758Speter return pclvalue( r , modflag , required ); 54758Speter # endif PC 552122Smckusic # ifdef OBJ 562122Smckusic /* 572122Smckusic * pi uses the rest of the function 582122Smckusic */ 59758Speter firstp = p = lookup(r[2]); 60758Speter if (p == NIL) { 61758Speter return (NIL); 62758Speter } 63758Speter c = r[3]; 64758Speter if ((modflag & NOUSE) && !lptr(c)) { 65758Speter p->nl_flags = flagwas; 66758Speter } 67758Speter if (modflag & MOD) { 68758Speter p->nl_flags |= NMOD; 69758Speter } 70758Speter /* 71758Speter * Only possibilities for p->class here 72758Speter * are the named classes, i.e. CONST, TYPE 73758Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 74758Speter */ 75758Speter switch (p->class) { 76758Speter case WITHPTR: 77758Speter /* 78758Speter * Construct the tree implied by 79758Speter * the with statement 80758Speter */ 81758Speter trp[0] = T_LISTPP; 82758Speter trp[1] = tr; 83758Speter trp[2] = r[3]; 84758Speter tr[0] = T_FIELD; 85758Speter tr[1] = r[2]; 86758Speter c = trp; 87758Speter # ifdef PTREE 88758Speter /* 89758Speter * mung r[4] to say which field this T_VAR is 90758Speter * for VarCopy 91758Speter */ 92758Speter r[4] = reclook( p -> type , r[2] ); 93758Speter # endif 94758Speter /* and fall through */ 95758Speter case REF: 96758Speter /* 97758Speter * Obtain the indirect word 98758Speter * of the WITHPTR or REF 99758Speter * as the base of our lvalue 100758Speter */ 1013074Smckusic put(2, PTR_RV | bn << 8+INDX , (int)p->value[0] ); 102758Speter f = 0; /* have an lv on stack */ 103758Speter o = 0; 104758Speter break; 105758Speter case VAR: 106758Speter f = 1; /* no lv on stack yet */ 107758Speter o = p->value[0]; 108758Speter break; 109758Speter default: 110758Speter error("%s %s found where variable required", classes[p->class], p->symbol); 111758Speter return (NIL); 112758Speter } 113758Speter /* 114758Speter * Loop and handle each 115758Speter * qualification on the name 116758Speter */ 1173581Speter if (c == NIL && (modflag&ASGN) && ( p->value[NL_FORV] & FORVAR ) ) { 118758Speter error("Can't modify the for variable %s in the range of the loop", p->symbol); 119758Speter return (NIL); 120758Speter } 121758Speter for (; c != NIL; c = c[2]) { 122758Speter co = c[1]; 123758Speter if (co == NIL) { 124758Speter return (NIL); 125758Speter } 126758Speter lastp = p; 127758Speter p = p->type; 128758Speter if (p == NIL) { 129758Speter return (NIL); 130758Speter } 131758Speter switch (co[0]) { 132758Speter case T_PTR: 133758Speter /* 134758Speter * Pointer qualification. 135758Speter */ 136758Speter lastp->nl_flags |= NUSED; 137758Speter if (p->class != PTR && p->class != FILET) { 138758Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 139758Speter goto bad; 140758Speter } 141758Speter if (f) { 1422071Smckusic if (p->class == FILET && bn != 0) 1432071Smckusic put(2, O_LV | bn <<8+INDX , o ); 1442071Smckusic else 1452071Smckusic /* 1462071Smckusic * this is the indirection from 1472071Smckusic * the address of the pointer 1482071Smckusic * to the pointer itself. 1492071Smckusic * kirk sez: 1502071Smckusic * fnil doesn't want this. 1512071Smckusic * and does it itself for files 1522071Smckusic * since only it knows where the 1532071Smckusic * actual window is. 1542071Smckusic * but i have to do this for 1552071Smckusic * regular pointers. 1562071Smckusic * This is further complicated by 1572071Smckusic * the fact that global variables 1582071Smckusic * are referenced through pointers 1592071Smckusic * on the stack. Thus an RV on a 1602071Smckusic * global variable is the same as 1612071Smckusic * an LV of a non-global one ?!? 1622071Smckusic */ 1632071Smckusic put(2, PTR_RV | bn <<8+INDX , o ); 164758Speter } else { 165758Speter if (o) { 1663074Smckusic put(2, O_OFF, o); 167758Speter } 1682104Smckusic if (p->class != FILET || bn == 0) 1692104Smckusic put(1, PTR_IND); 170758Speter } 171758Speter /* 172758Speter * Pointer cannot be 173758Speter * nil and file cannot 174758Speter * be at end-of-file. 175758Speter */ 1763074Smckusic put(1, p->class == FILET ? O_FNIL : O_NIL); 177758Speter f = o = 0; 178758Speter continue; 179758Speter case T_ARGL: 180758Speter if (p->class != ARRAY) { 181758Speter if (lastp == firstp) { 182758Speter error("%s is a %s, not a function", r[2], classes[firstp->class]); 183758Speter } else { 184758Speter error("Illegal function qualificiation"); 185758Speter } 186758Speter return (NIL); 187758Speter } 188758Speter recovered(); 189758Speter error("Pascal uses [] for subscripting, not ()"); 190758Speter case T_ARY: 191758Speter if (p->class != ARRAY) { 192758Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 193758Speter goto bad; 194758Speter } 195758Speter if (f) { 1962071Smckusic if (bn == 0) 1972071Smckusic /* 1982071Smckusic * global variables are 1992071Smckusic * referenced through pointers 2002071Smckusic * on the stack 2012071Smckusic */ 2023074Smckusic put(2, PTR_RV | bn<<8+INDX, o); 2032071Smckusic else 2043074Smckusic put(2, O_LV | bn<<8+INDX, o); 205758Speter } else { 206758Speter if (o) { 2073074Smckusic put(2, O_OFF, o); 208758Speter } 209758Speter } 210758Speter switch (arycod(p, co[1])) { 211758Speter case 0: 212758Speter return (NIL); 213758Speter case -1: 214758Speter goto bad; 215758Speter } 216758Speter f = o = 0; 217758Speter continue; 218758Speter case T_FIELD: 219758Speter /* 220758Speter * Field names are just 221758Speter * an offset with some 222758Speter * semantic checking. 223758Speter */ 224758Speter if (p->class != RECORD) { 225758Speter error(". allowed only on records, not on %ss", nameof(p)); 226758Speter goto bad; 227758Speter } 228758Speter if (co[1] == NIL) { 229758Speter return (NIL); 230758Speter } 231758Speter p = reclook(p, co[1]); 232758Speter if (p == NIL) { 233758Speter error("%s is not a field in this record", co[1]); 234758Speter goto bad; 235758Speter } 236758Speter # ifdef PTREE 237758Speter /* 238758Speter * mung co[3] to indicate which field 239758Speter * this is for SelCopy 240758Speter */ 241758Speter co[3] = p; 242758Speter # endif 243758Speter if (modflag & MOD) { 244758Speter p->nl_flags |= NMOD; 245758Speter } 246758Speter if ((modflag & NOUSE) == 0 || lptr(c[2])) { 247758Speter p->nl_flags |= NUSED; 248758Speter } 249758Speter o += p->value[0]; 250758Speter continue; 251758Speter default: 252758Speter panic("lval2"); 253758Speter } 254758Speter } 255758Speter if (f) { 2562071Smckusic if (bn == 0) 2572071Smckusic /* 2582071Smckusic * global variables are referenced through 2592071Smckusic * pointers on the stack 2602071Smckusic */ 2613074Smckusic put(2, PTR_RV | bn<<8+INDX, o); 2622071Smckusic else 2633074Smckusic put(2, O_LV | bn<<8+INDX, o); 264758Speter } else { 265758Speter if (o) { 2663074Smckusic put(2, O_OFF, o); 267758Speter } 268758Speter } 269758Speter return (p->type); 270758Speter bad: 271758Speter cerror("Error occurred on qualification of %s", r[2]); 272758Speter return (NIL); 2732122Smckusic # endif OBJ 274758Speter } 275758Speter 276758Speter lptr(c) 277758Speter register int *c; 278758Speter { 279758Speter register int *co; 280758Speter 281758Speter for (; c != NIL; c = c[2]) { 282758Speter co = c[1]; 283758Speter if (co == NIL) { 284758Speter return (NIL); 285758Speter } 286758Speter switch (co[0]) { 287758Speter 288758Speter case T_PTR: 289758Speter return (1); 290758Speter case T_ARGL: 291758Speter return (0); 292758Speter case T_ARY: 293758Speter case T_FIELD: 294758Speter continue; 295758Speter default: 296758Speter panic("lptr"); 297758Speter } 298758Speter } 299758Speter return (0); 300758Speter } 301758Speter 302758Speter /* 303758Speter * Arycod does the 304758Speter * code generation 305758Speter * for subscripting. 306758Speter */ 307758Speter arycod(np, el) 308758Speter struct nl *np; 309758Speter int *el; 310758Speter { 311758Speter register struct nl *p, *ap; 3123890Smckusic long sub; 3133890Smckusic bool constsub; 314758Speter int i, d, v, v1; 315758Speter int w; 316758Speter 317758Speter p = np; 318758Speter if (el == NIL) { 319758Speter return (0); 320758Speter } 321758Speter d = p->value[0]; 322758Speter /* 323758Speter * Check each subscript 324758Speter */ 325758Speter for (i = 1; i <= d; i++) { 326758Speter if (el == NIL) { 327758Speter error("Too few subscripts (%d given, %d required)", i-1, d); 328758Speter return (-1); 329758Speter } 330758Speter p = p->chain; 3313890Smckusic if (constsub = constval(el[1])) { 3323890Smckusic ap = con.ctype; 3333890Smckusic sub = con.crval; 3343890Smckusic if (sub < p->range[0] || sub > p->range[1]) { 3353890Smckusic error("Subscript value of %D is out of range", sub); 336758Speter return (0); 3373890Smckusic } 3383890Smckusic sub -= p->range[0]; 3393890Smckusic } else { 3403890Smckusic # ifdef PC 3413890Smckusic precheck( p , "_SUBSC" , "_SUBSCZ" ); 3423890Smckusic # endif PC 3433890Smckusic ap = rvalue(el[1], NLNIL , RREQ ); 3443890Smckusic if (ap == NIL) { 3453890Smckusic return (0); 3463890Smckusic } 3473890Smckusic # ifdef PC 348*10361Smckusick postcheck(p, ap); 349*10361Smckusick sconv(p2type(ap),P2INT); 3503890Smckusic # endif PC 351758Speter } 352758Speter if (incompat(ap, p->type, el[1])) { 353758Speter cerror("Array index type incompatible with declared index type"); 354758Speter if (d != 1) { 355758Speter cerror("Error occurred on index number %d", i); 356758Speter } 357758Speter return (-1); 358758Speter } 359758Speter w = aryconst(np, i); 360758Speter # ifdef OBJ 3613890Smckusic if (constsub) { 3623890Smckusic sub *= w; 3633890Smckusic if (sub != 0) { 3643890Smckusic w = width(ap); 3653890Smckusic put(2, w <= 2 ? O_CON2 : O_CON4, sub); 3663890Smckusic gen(NIL, T_ADD, sizeof(char *), w); 3673890Smckusic } 3683890Smckusic el = el[2]; 3693890Smckusic continue; 3703890Smckusic } 371758Speter if (opt('t') == 0) { 372758Speter switch (w) { 373758Speter case 8: 374758Speter w = 6; 375758Speter case 4: 376758Speter case 2: 377758Speter case 1: 3783074Smckusic put(2, (width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]); 379758Speter el = el[2]; 380758Speter continue; 381758Speter } 382758Speter } 3833074Smckusic put(4, width(ap) != 4 ? O_INX2 : O_INX4, w, 3843074Smckusic (short)p->range[0], (short)(p->range[1])); 3853890Smckusic el = el[2]; 3863890Smckusic continue; 387758Speter # endif OBJ 388758Speter # ifdef PC 389758Speter /* 390758Speter * subtract off the lower bound 391758Speter */ 3923890Smckusic if (constsub) { 3933890Smckusic sub *= w; 3943890Smckusic if (sub != 0) { 3953890Smckusic putleaf( P2ICON , sub , 0 , P2INT , 0 ); 3963890Smckusic putop(P2PLUS, ADDTYPE(p2type(np->type), P2PTR)); 3973890Smckusic } 3983890Smckusic el = el[2]; 3993890Smckusic continue; 4003890Smckusic } 401758Speter if ( p -> range[ 0 ] != 0 ) { 402758Speter putleaf( P2ICON , p -> range[0] , 0 , P2INT , 0 ); 403758Speter putop( P2MINUS , P2INT ); 404758Speter } 405758Speter /* 406758Speter * multiply by the width of the elements 407758Speter */ 408758Speter if ( w != 1 ) { 409758Speter putleaf( P2ICON , w , 0 , P2INT , 0 ); 410758Speter putop( P2MUL , P2INT ); 411758Speter } 412758Speter /* 413758Speter * and add it to the base address 414758Speter */ 415758Speter putop( P2PLUS , ADDTYPE( p2type( np -> type ) , P2PTR ) ); 416758Speter # endif PC 417758Speter el = el[2]; 418758Speter } 419758Speter if (el != NIL) { 420758Speter do { 421758Speter el = el[2]; 422758Speter i++; 423758Speter } while (el != NIL); 424758Speter error("Too many subscripts (%d given, %d required)", i-1, d); 425758Speter return (-1); 426758Speter } 427758Speter return (1); 428758Speter } 429