1758Speter /* Copyright (c) 1979 Regents of the University of California */ 2758Speter 3*2104Smckusic static char sccsid[] = "@(#)lval.c 1.3 01/10/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) { 1382071Smckusic if (p->class == FILET && bn != 0) 1392071Smckusic put(2, O_LV | bn <<8+INDX , o ); 1402071Smckusic else 1412071Smckusic /* 1422071Smckusic * this is the indirection from 1432071Smckusic * the address of the pointer 1442071Smckusic * to the pointer itself. 1452071Smckusic * kirk sez: 1462071Smckusic * fnil doesn't want this. 1472071Smckusic * and does it itself for files 1482071Smckusic * since only it knows where the 1492071Smckusic * actual window is. 1502071Smckusic * but i have to do this for 1512071Smckusic * regular pointers. 1522071Smckusic * This is further complicated by 1532071Smckusic * the fact that global variables 1542071Smckusic * are referenced through pointers 1552071Smckusic * on the stack. Thus an RV on a 1562071Smckusic * global variable is the same as 1572071Smckusic * an LV of a non-global one ?!? 1582071Smckusic */ 1592071Smckusic put(2, PTR_RV | bn <<8+INDX , o ); 160758Speter } else { 161758Speter if (o) { 162758Speter put2(O_OFF, o); 163758Speter } 164*2104Smckusic if (p->class != FILET || bn == 0) 165*2104Smckusic put(1, PTR_IND); 166758Speter } 167758Speter /* 168758Speter * Pointer cannot be 169758Speter * nil and file cannot 170758Speter * be at end-of-file. 171758Speter */ 172758Speter put1(p->class == FILET ? O_FNIL : O_NIL); 173758Speter f = o = 0; 174758Speter continue; 175758Speter case T_ARGL: 176758Speter if (p->class != ARRAY) { 177758Speter if (lastp == firstp) { 178758Speter error("%s is a %s, not a function", r[2], classes[firstp->class]); 179758Speter } else { 180758Speter error("Illegal function qualificiation"); 181758Speter } 182758Speter return (NIL); 183758Speter } 184758Speter recovered(); 185758Speter error("Pascal uses [] for subscripting, not ()"); 186758Speter case T_ARY: 187758Speter if (p->class != ARRAY) { 188758Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 189758Speter goto bad; 190758Speter } 191758Speter if (f) { 1922071Smckusic if (bn == 0) 1932071Smckusic /* 1942071Smckusic * global variables are 1952071Smckusic * referenced through pointers 1962071Smckusic * on the stack 1972071Smckusic */ 1982071Smckusic put2(PTR_RV | bn<<8+INDX, o); 1992071Smckusic else 2002071Smckusic put2(O_LV | bn<<8+INDX, o); 201758Speter } else { 202758Speter if (o) { 203758Speter put2(O_OFF, o); 204758Speter } 205758Speter } 206758Speter switch (arycod(p, co[1])) { 207758Speter case 0: 208758Speter return (NIL); 209758Speter case -1: 210758Speter goto bad; 211758Speter } 212758Speter f = o = 0; 213758Speter continue; 214758Speter case T_FIELD: 215758Speter /* 216758Speter * Field names are just 217758Speter * an offset with some 218758Speter * semantic checking. 219758Speter */ 220758Speter if (p->class != RECORD) { 221758Speter error(". allowed only on records, not on %ss", nameof(p)); 222758Speter goto bad; 223758Speter } 224758Speter if (co[1] == NIL) { 225758Speter return (NIL); 226758Speter } 227758Speter p = reclook(p, co[1]); 228758Speter if (p == NIL) { 229758Speter error("%s is not a field in this record", co[1]); 230758Speter goto bad; 231758Speter } 232758Speter # ifdef PTREE 233758Speter /* 234758Speter * mung co[3] to indicate which field 235758Speter * this is for SelCopy 236758Speter */ 237758Speter co[3] = p; 238758Speter # endif 239758Speter if (modflag & MOD) { 240758Speter p->nl_flags |= NMOD; 241758Speter } 242758Speter if ((modflag & NOUSE) == 0 || lptr(c[2])) { 243758Speter p->nl_flags |= NUSED; 244758Speter } 245758Speter o += p->value[0]; 246758Speter continue; 247758Speter default: 248758Speter panic("lval2"); 249758Speter } 250758Speter } 251758Speter if (f) { 2522071Smckusic if (bn == 0) 2532071Smckusic /* 2542071Smckusic * global variables are referenced through 2552071Smckusic * pointers on the stack 2562071Smckusic */ 2572071Smckusic put2(PTR_RV | bn<<8+INDX, o); 2582071Smckusic else 2592071Smckusic put2(O_LV | bn<<8+INDX, o); 260758Speter } else { 261758Speter if (o) { 262758Speter put2(O_OFF, o); 263758Speter } 264758Speter } 265758Speter return (p->type); 266758Speter bad: 267758Speter cerror("Error occurred on qualification of %s", r[2]); 268758Speter return (NIL); 269758Speter } 270758Speter 271758Speter lptr(c) 272758Speter register int *c; 273758Speter { 274758Speter register int *co; 275758Speter 276758Speter for (; c != NIL; c = c[2]) { 277758Speter co = c[1]; 278758Speter if (co == NIL) { 279758Speter return (NIL); 280758Speter } 281758Speter switch (co[0]) { 282758Speter 283758Speter case T_PTR: 284758Speter return (1); 285758Speter case T_ARGL: 286758Speter return (0); 287758Speter case T_ARY: 288758Speter case T_FIELD: 289758Speter continue; 290758Speter default: 291758Speter panic("lptr"); 292758Speter } 293758Speter } 294758Speter return (0); 295758Speter } 296758Speter 297758Speter /* 298758Speter * Arycod does the 299758Speter * code generation 300758Speter * for subscripting. 301758Speter */ 302758Speter arycod(np, el) 303758Speter struct nl *np; 304758Speter int *el; 305758Speter { 306758Speter register struct nl *p, *ap; 307758Speter int i, d, v, v1; 308758Speter int w; 309758Speter 310758Speter p = np; 311758Speter if (el == NIL) { 312758Speter return (0); 313758Speter } 314758Speter d = p->value[0]; 315758Speter /* 316758Speter * Check each subscript 317758Speter */ 318758Speter for (i = 1; i <= d; i++) { 319758Speter if (el == NIL) { 320758Speter error("Too few subscripts (%d given, %d required)", i-1, d); 321758Speter return (-1); 322758Speter } 323758Speter p = p->chain; 324758Speter # ifdef PC 325758Speter precheck( p , "_SUBSC" , "_SUBSCZ" ); 326758Speter # endif PC 327758Speter ap = rvalue(el[1], NLNIL , RREQ ); 328758Speter if (ap == NIL) { 329758Speter return (0); 330758Speter } 331758Speter # ifdef PC 332758Speter postcheck( p ); 333758Speter # endif PC 334758Speter if (incompat(ap, p->type, el[1])) { 335758Speter cerror("Array index type incompatible with declared index type"); 336758Speter if (d != 1) { 337758Speter cerror("Error occurred on index number %d", i); 338758Speter } 339758Speter return (-1); 340758Speter } 341758Speter w = aryconst(np, i); 342758Speter # ifdef OBJ 343758Speter if (opt('t') == 0) { 344758Speter switch (w) { 345758Speter case 8: 346758Speter w = 6; 347758Speter case 4: 348758Speter case 2: 349758Speter case 1: 350758Speter put2((width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]); 351758Speter el = el[2]; 352758Speter continue; 353758Speter } 354758Speter } 355758Speter put(4, width(ap) != 4 ? O_INX2 : O_INX4,w,( short ) p->range[0], 356*2104Smckusic ( short ) ( p->range[1] ) ); 357758Speter # endif OBJ 358758Speter # ifdef PC 359758Speter /* 360758Speter * subtract off the lower bound 361758Speter */ 362758Speter if ( p -> range[ 0 ] != 0 ) { 363758Speter putleaf( P2ICON , p -> range[0] , 0 , P2INT , 0 ); 364758Speter putop( P2MINUS , P2INT ); 365758Speter } 366758Speter /* 367758Speter * multiply by the width of the elements 368758Speter */ 369758Speter if ( w != 1 ) { 370758Speter putleaf( P2ICON , w , 0 , P2INT , 0 ); 371758Speter putop( P2MUL , P2INT ); 372758Speter } 373758Speter /* 374758Speter * and add it to the base address 375758Speter */ 376758Speter putop( P2PLUS , ADDTYPE( p2type( np -> type ) , P2PTR ) ); 377758Speter # endif PC 378758Speter el = el[2]; 379758Speter } 380758Speter if (el != NIL) { 381758Speter do { 382758Speter el = el[2]; 383758Speter i++; 384758Speter } while (el != NIL); 385758Speter error("Too many subscripts (%d given, %d required)", i-1, d); 386758Speter return (-1); 387758Speter } 388758Speter return (1); 389758Speter } 390