1758Speter /* Copyright (c) 1979 Regents of the University of California */ 2758Speter 3*2071Smckusic static char sccsid[] = "@(#)lval.c 1.2 01/06/81"; 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 55758Speter firstp = p = lookup(r[2]); 56758Speter if (p == NIL) { 57758Speter return (NIL); 58758Speter } 59758Speter c = r[3]; 60758Speter if ((modflag & NOUSE) && !lptr(c)) { 61758Speter p->nl_flags = flagwas; 62758Speter } 63758Speter if (modflag & MOD) { 64758Speter p->nl_flags |= NMOD; 65758Speter } 66758Speter /* 67758Speter * Only possibilities for p->class here 68758Speter * are the named classes, i.e. CONST, TYPE 69758Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 70758Speter */ 71758Speter switch (p->class) { 72758Speter case WITHPTR: 73758Speter /* 74758Speter * Construct the tree implied by 75758Speter * the with statement 76758Speter */ 77758Speter trp[0] = T_LISTPP; 78758Speter trp[1] = tr; 79758Speter trp[2] = r[3]; 80758Speter tr[0] = T_FIELD; 81758Speter tr[1] = r[2]; 82758Speter c = trp; 83758Speter # ifdef PTREE 84758Speter /* 85758Speter * mung r[4] to say which field this T_VAR is 86758Speter * for VarCopy 87758Speter */ 88758Speter r[4] = reclook( p -> type , r[2] ); 89758Speter # endif 90758Speter /* and fall through */ 91758Speter case REF: 92758Speter /* 93758Speter * Obtain the indirect word 94758Speter * of the WITHPTR or REF 95758Speter * as the base of our lvalue 96758Speter */ 97758Speter put(2, PTR_RV | bn << 8+INDX , p->value[0] ); 98758Speter f = 0; /* have an lv on stack */ 99758Speter o = 0; 100758Speter break; 101758Speter case VAR: 102758Speter f = 1; /* no lv on stack yet */ 103758Speter o = p->value[0]; 104758Speter break; 105758Speter default: 106758Speter error("%s %s found where variable required", classes[p->class], p->symbol); 107758Speter return (NIL); 108758Speter } 109758Speter /* 110758Speter * Loop and handle each 111758Speter * qualification on the name 112758Speter */ 113758Speter if (c == NIL && (modflag&ASGN) && p->value[NL_FORV]) { 114758Speter error("Can't modify the for variable %s in the range of the loop", p->symbol); 115758Speter return (NIL); 116758Speter } 117758Speter for (; c != NIL; c = c[2]) { 118758Speter co = c[1]; 119758Speter if (co == NIL) { 120758Speter return (NIL); 121758Speter } 122758Speter lastp = p; 123758Speter p = p->type; 124758Speter if (p == NIL) { 125758Speter return (NIL); 126758Speter } 127758Speter switch (co[0]) { 128758Speter case T_PTR: 129758Speter /* 130758Speter * Pointer qualification. 131758Speter */ 132758Speter lastp->nl_flags |= NUSED; 133758Speter if (p->class != PTR && p->class != FILET) { 134758Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 135758Speter goto bad; 136758Speter } 137758Speter if (f) { 138*2071Smckusic if (p->class == FILET && bn != 0) 139*2071Smckusic put(2, O_LV | bn <<8+INDX , o ); 140*2071Smckusic else 141*2071Smckusic /* 142*2071Smckusic * this is the indirection from 143*2071Smckusic * the address of the pointer 144*2071Smckusic * to the pointer itself. 145*2071Smckusic * kirk sez: 146*2071Smckusic * fnil doesn't want this. 147*2071Smckusic * and does it itself for files 148*2071Smckusic * since only it knows where the 149*2071Smckusic * actual window is. 150*2071Smckusic * but i have to do this for 151*2071Smckusic * regular pointers. 152*2071Smckusic * This is further complicated by 153*2071Smckusic * the fact that global variables 154*2071Smckusic * are referenced through pointers 155*2071Smckusic * on the stack. Thus an RV on a 156*2071Smckusic * global variable is the same as 157*2071Smckusic * an LV of a non-global one ?!? 158*2071Smckusic */ 159*2071Smckusic put(2, PTR_RV | bn <<8+INDX , o ); 160758Speter } else { 161758Speter if (o) { 162758Speter put2(O_OFF, o); 163758Speter } 164758Speter put(1, PTR_IND); 165758Speter } 166758Speter /* 167758Speter * Pointer cannot be 168758Speter * nil and file cannot 169758Speter * be at end-of-file. 170758Speter */ 171758Speter put1(p->class == FILET ? O_FNIL : O_NIL); 172758Speter f = o = 0; 173758Speter continue; 174758Speter case T_ARGL: 175758Speter if (p->class != ARRAY) { 176758Speter if (lastp == firstp) { 177758Speter error("%s is a %s, not a function", r[2], classes[firstp->class]); 178758Speter } else { 179758Speter error("Illegal function qualificiation"); 180758Speter } 181758Speter return (NIL); 182758Speter } 183758Speter recovered(); 184758Speter error("Pascal uses [] for subscripting, not ()"); 185758Speter case T_ARY: 186758Speter if (p->class != ARRAY) { 187758Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 188758Speter goto bad; 189758Speter } 190758Speter if (f) { 191*2071Smckusic if (bn == 0) 192*2071Smckusic /* 193*2071Smckusic * global variables are 194*2071Smckusic * referenced through pointers 195*2071Smckusic * on the stack 196*2071Smckusic */ 197*2071Smckusic put2(PTR_RV | bn<<8+INDX, o); 198*2071Smckusic else 199*2071Smckusic put2(O_LV | bn<<8+INDX, o); 200758Speter } else { 201758Speter if (o) { 202758Speter put2(O_OFF, o); 203758Speter } 204758Speter } 205758Speter switch (arycod(p, co[1])) { 206758Speter case 0: 207758Speter return (NIL); 208758Speter case -1: 209758Speter goto bad; 210758Speter } 211758Speter f = o = 0; 212758Speter continue; 213758Speter case T_FIELD: 214758Speter /* 215758Speter * Field names are just 216758Speter * an offset with some 217758Speter * semantic checking. 218758Speter */ 219758Speter if (p->class != RECORD) { 220758Speter error(". allowed only on records, not on %ss", nameof(p)); 221758Speter goto bad; 222758Speter } 223758Speter if (co[1] == NIL) { 224758Speter return (NIL); 225758Speter } 226758Speter p = reclook(p, co[1]); 227758Speter if (p == NIL) { 228758Speter error("%s is not a field in this record", co[1]); 229758Speter goto bad; 230758Speter } 231758Speter # ifdef PTREE 232758Speter /* 233758Speter * mung co[3] to indicate which field 234758Speter * this is for SelCopy 235758Speter */ 236758Speter co[3] = p; 237758Speter # endif 238758Speter if (modflag & MOD) { 239758Speter p->nl_flags |= NMOD; 240758Speter } 241758Speter if ((modflag & NOUSE) == 0 || lptr(c[2])) { 242758Speter p->nl_flags |= NUSED; 243758Speter } 244758Speter o += p->value[0]; 245758Speter continue; 246758Speter default: 247758Speter panic("lval2"); 248758Speter } 249758Speter } 250758Speter if (f) { 251*2071Smckusic if (bn == 0) 252*2071Smckusic /* 253*2071Smckusic * global variables are referenced through 254*2071Smckusic * pointers on the stack 255*2071Smckusic */ 256*2071Smckusic put2(PTR_RV | bn<<8+INDX, o); 257*2071Smckusic else 258*2071Smckusic put2(O_LV | bn<<8+INDX, o); 259758Speter } else { 260758Speter if (o) { 261758Speter put2(O_OFF, o); 262758Speter } 263758Speter } 264758Speter return (p->type); 265758Speter bad: 266758Speter cerror("Error occurred on qualification of %s", r[2]); 267758Speter return (NIL); 268758Speter } 269758Speter 270758Speter lptr(c) 271758Speter register int *c; 272758Speter { 273758Speter register int *co; 274758Speter 275758Speter for (; c != NIL; c = c[2]) { 276758Speter co = c[1]; 277758Speter if (co == NIL) { 278758Speter return (NIL); 279758Speter } 280758Speter switch (co[0]) { 281758Speter 282758Speter case T_PTR: 283758Speter return (1); 284758Speter case T_ARGL: 285758Speter return (0); 286758Speter case T_ARY: 287758Speter case T_FIELD: 288758Speter continue; 289758Speter default: 290758Speter panic("lptr"); 291758Speter } 292758Speter } 293758Speter return (0); 294758Speter } 295758Speter 296758Speter /* 297758Speter * Arycod does the 298758Speter * code generation 299758Speter * for subscripting. 300758Speter */ 301758Speter arycod(np, el) 302758Speter struct nl *np; 303758Speter int *el; 304758Speter { 305758Speter register struct nl *p, *ap; 306758Speter int i, d, v, v1; 307758Speter int w; 308758Speter 309758Speter p = np; 310758Speter if (el == NIL) { 311758Speter return (0); 312758Speter } 313758Speter d = p->value[0]; 314758Speter /* 315758Speter * Check each subscript 316758Speter */ 317758Speter for (i = 1; i <= d; i++) { 318758Speter if (el == NIL) { 319758Speter error("Too few subscripts (%d given, %d required)", i-1, d); 320758Speter return (-1); 321758Speter } 322758Speter p = p->chain; 323758Speter # ifdef PC 324758Speter precheck( p , "_SUBSC" , "_SUBSCZ" ); 325758Speter # endif PC 326758Speter ap = rvalue(el[1], NLNIL , RREQ ); 327758Speter if (ap == NIL) { 328758Speter return (0); 329758Speter } 330758Speter # ifdef PC 331758Speter postcheck( p ); 332758Speter # endif PC 333758Speter if (incompat(ap, p->type, el[1])) { 334758Speter cerror("Array index type incompatible with declared index type"); 335758Speter if (d != 1) { 336758Speter cerror("Error occurred on index number %d", i); 337758Speter } 338758Speter return (-1); 339758Speter } 340758Speter w = aryconst(np, i); 341758Speter # ifdef OBJ 342758Speter if (opt('t') == 0) { 343758Speter switch (w) { 344758Speter case 8: 345758Speter w = 6; 346758Speter case 4: 347758Speter case 2: 348758Speter case 1: 349758Speter put2((width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]); 350758Speter el = el[2]; 351758Speter continue; 352758Speter } 353758Speter } 354758Speter put(4, width(ap) != 4 ? O_INX2 : O_INX4,w,( short ) p->range[0], 355758Speter ( short ) ( p->range[1] - p->range[0] ) ); 356758Speter # endif OBJ 357758Speter # ifdef PC 358758Speter /* 359758Speter * subtract off the lower bound 360758Speter */ 361758Speter if ( p -> range[ 0 ] != 0 ) { 362758Speter putleaf( P2ICON , p -> range[0] , 0 , P2INT , 0 ); 363758Speter putop( P2MINUS , P2INT ); 364758Speter } 365758Speter /* 366758Speter * multiply by the width of the elements 367758Speter */ 368758Speter if ( w != 1 ) { 369758Speter putleaf( P2ICON , w , 0 , P2INT , 0 ); 370758Speter putop( P2MUL , P2INT ); 371758Speter } 372758Speter /* 373758Speter * and add it to the base address 374758Speter */ 375758Speter putop( P2PLUS , ADDTYPE( p2type( np -> type ) , P2PTR ) ); 376758Speter # endif PC 377758Speter el = el[2]; 378758Speter } 379758Speter if (el != NIL) { 380758Speter do { 381758Speter el = el[2]; 382758Speter i++; 383758Speter } while (el != NIL); 384758Speter error("Too many subscripts (%d given, %d required)", i-1, d); 385758Speter return (-1); 386758Speter } 387758Speter return (1); 388758Speter } 389