1758Speter /* Copyright (c) 1979 Regents of the University of California */ 2758Speter 3*15932Smckusick #ifndef lint 4*15932Smckusick static char sccsid[] = "@(#)lval.c 1.9.1.1 02/04/84"; 5*15932Smckusick #endif 6758Speter 7758Speter #include "whoami.h" 8758Speter #include "0.h" 9758Speter #include "tree.h" 10758Speter #include "opcode.h" 11758Speter #include "objfmt.h" 12*15932Smckusick #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 */ 26*15932Smckusick /*ARGSUSED*/ 27758Speter struct nl * 28*15932Smckusick lvalue(var, modflag , required ) 29*15932Smckusick struct tnode *var; 30*15932Smckusick int modflag; 31758Speter int required; 32758Speter { 33*15932Smckusick #ifdef OBJ 34758Speter register struct nl *p; 35758Speter struct nl *firstp, *lastp; 36*15932Smckusick register struct tnode *c, *co; 37758Speter int f, o; 38758Speter /* 39758Speter * Note that the local optimizations 40758Speter * done here for offsets would more 41758Speter * appropriately be done in put. 42758Speter */ 43*15932Smckusick struct tnode tr; /* T_FIELD */ 44*15932Smckusick struct tnode *tr_ptr; 45*15932Smckusick struct tnode l_node; 46*15932Smckusick #endif 47758Speter 48*15932Smckusick if (var == TR_NIL) { 49*15932Smckusick return (NLNIL); 50758Speter } 51*15932Smckusick if (nowexp(var)) { 52*15932Smckusick return (NLNIL); 53758Speter } 54*15932Smckusick if (var->tag != T_VAR) { 55758Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 56*15932Smckusick return (NLNIL); 57758Speter } 58758Speter # ifdef PC 59758Speter /* 60758Speter * pc requires a whole different control flow 61758Speter */ 62*15932Smckusick return pclvalue( var , modflag , required ); 63758Speter # endif PC 642122Smckusic # ifdef OBJ 652122Smckusic /* 662122Smckusic * pi uses the rest of the function 672122Smckusic */ 68*15932Smckusick firstp = p = lookup(var->var_node.cptr); 69*15932Smckusick if (p == NLNIL) { 70*15932Smckusick return (NLNIL); 71758Speter } 72*15932Smckusick 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 */ 84*15932Smckusick tr_ptr = &l_node; 85758Speter switch (p->class) { 86758Speter case WITHPTR: 87758Speter /* 88758Speter * Construct the tree implied by 89758Speter * the with statement 90758Speter */ 91*15932Smckusick l_node.tag = T_LISTPP; 92*15932Smckusick 93*15932Smckusick /* the cast has got to go but until the node is figured 94*15932Smckusick out it stays */ 95*15932Smckusick 96*15932Smckusick tr_ptr->list_node.list = (&tr); 97*15932Smckusick tr_ptr->list_node.next = var->var_node.qual; 98*15932Smckusick tr.tag = T_FIELD; 99*15932Smckusick tr.field_node.id_ptr = var->var_node.cptr; 100*15932Smckusick c = tr_ptr; /* c is a ptr to a tnode */ 101758Speter # ifdef PTREE 102758Speter /* 103*15932Smckusick * mung var->fields to say which field this T_VAR is 104758Speter * for VarCopy 105758Speter */ 106*15932Smckusick 107*15932Smckusick /* problem! reclook returns struct nl* */ 108*15932Smckusick 109*15932Smckusick var->var_node.fields = reclook( p -> type , 110*15932Smckusick 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 */ 119*15932Smckusick (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: 124758Speter f = 1; /* no lv on stack yet */ 125758Speter o = p->value[0]; 126758Speter break; 127758Speter default: 128758Speter error("%s %s found where variable required", classes[p->class], p->symbol); 129*15932Smckusick return (NLNIL); 130758Speter } 131758Speter /* 132758Speter * Loop and handle each 133758Speter * qualification on the name 134758Speter */ 135*15932Smckusick if (c == TR_NIL && (modflag&ASGN) && ( p->value[NL_FORV] & FORVAR ) ) { 136758Speter error("Can't modify the for variable %s in the range of the loop", p->symbol); 137*15932Smckusick return (NLNIL); 138758Speter } 139*15932Smckusick for (; c != TR_NIL; c = c->list_node.next) { 140*15932Smckusick co = c->list_node.list; /* co is a ptr to a tnode */ 141*15932Smckusick if (co == TR_NIL) { 142*15932Smckusick return (NLNIL); 143758Speter } 144758Speter lastp = p; 145758Speter p = p->type; 146*15932Smckusick if (p == NLNIL) { 147*15932Smckusick return (NLNIL); 148758Speter } 149*15932Smckusick switch (co->tag) { 150758Speter case T_PTR: 151758Speter /* 152758Speter * Pointer qualification. 153758Speter */ 154758Speter lastp->nl_flags |= NUSED; 155758Speter if (p->class != PTR && p->class != FILET) { 156758Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 157758Speter goto bad; 158758Speter } 159758Speter if (f) { 1602071Smckusic if (p->class == FILET && bn != 0) 161*15932Smckusick (void) put(2, O_LV | bn <<8+INDX , o ); 1622071Smckusic else 1632071Smckusic /* 1642071Smckusic * this is the indirection from 1652071Smckusic * the address of the pointer 1662071Smckusic * to the pointer itself. 1672071Smckusic * kirk sez: 1682071Smckusic * fnil doesn't want this. 1692071Smckusic * and does it itself for files 1702071Smckusic * since only it knows where the 1712071Smckusic * actual window is. 1722071Smckusic * but i have to do this for 1732071Smckusic * regular pointers. 1742071Smckusic * This is further complicated by 1752071Smckusic * the fact that global variables 1762071Smckusic * are referenced through pointers 1772071Smckusic * on the stack. Thus an RV on a 1782071Smckusic * global variable is the same as 1792071Smckusic * an LV of a non-global one ?!? 1802071Smckusic */ 181*15932Smckusick (void) put(2, PTR_RV | bn <<8+INDX , o ); 182758Speter } else { 183758Speter if (o) { 184*15932Smckusick (void) put(2, O_OFF, o); 185758Speter } 1862104Smckusic if (p->class != FILET || bn == 0) 187*15932Smckusick (void) put(1, PTR_IND); 188758Speter } 189758Speter /* 190758Speter * Pointer cannot be 191758Speter * nil and file cannot 192758Speter * be at end-of-file. 193758Speter */ 194*15932Smckusick (void) put(1, p->class == FILET ? O_FNIL : O_NIL); 195758Speter f = o = 0; 196758Speter continue; 197758Speter case T_ARGL: 198758Speter if (p->class != ARRAY) { 199758Speter if (lastp == firstp) { 200*15932Smckusick error("%s is a %s, not a function", var->var_node.cptr, classes[firstp->class]); 201758Speter } else { 202758Speter error("Illegal function qualificiation"); 203758Speter } 204*15932Smckusick return (NLNIL); 205758Speter } 206758Speter recovered(); 207758Speter error("Pascal uses [] for subscripting, not ()"); 208758Speter case T_ARY: 209758Speter if (p->class != ARRAY) { 210758Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 211758Speter goto bad; 212758Speter } 213758Speter if (f) { 2142071Smckusic if (bn == 0) 2152071Smckusic /* 2162071Smckusic * global variables are 2172071Smckusic * referenced through pointers 2182071Smckusic * on the stack 2192071Smckusic */ 220*15932Smckusick (void) put(2, PTR_RV | bn<<8+INDX, o); 2212071Smckusic else 222*15932Smckusick (void) put(2, O_LV | bn<<8+INDX, o); 223758Speter } else { 224758Speter if (o) { 225*15932Smckusick (void) put(2, O_OFF, o); 226758Speter } 227758Speter } 228*15932Smckusick switch (arycod(p, co->ary_node.expr_list)) { 229758Speter case 0: 230*15932Smckusick return (NLNIL); 231758Speter case -1: 232758Speter goto bad; 233758Speter } 234758Speter f = o = 0; 235758Speter continue; 236758Speter case T_FIELD: 237758Speter /* 238758Speter * Field names are just 239758Speter * an offset with some 240758Speter * semantic checking. 241758Speter */ 242758Speter if (p->class != RECORD) { 243758Speter error(". allowed only on records, not on %ss", nameof(p)); 244758Speter goto bad; 245758Speter } 246*15932Smckusick /* must define the field node!! */ 247*15932Smckusick if (co->field_node.id_ptr == NIL) { 248*15932Smckusick return (NLNIL); 249758Speter } 250*15932Smckusick p = reclook(p, co->field_node.id_ptr); 251*15932Smckusick if (p == NLNIL) { 252*15932Smckusick error("%s is not a field in this record", co->field_node.id_ptr); 253758Speter goto bad; 254758Speter } 255758Speter # ifdef PTREE 256758Speter /* 257758Speter * mung co[3] to indicate which field 258758Speter * this is for SelCopy 259758Speter */ 260*15932Smckusick co->field_node.nl_entry = p; 261758Speter # endif 262758Speter if (modflag & MOD) { 263758Speter p->nl_flags |= NMOD; 264758Speter } 265*15932Smckusick if ((modflag & NOUSE) == 0 || 266*15932Smckusick lptr(c->list_node.next)) { 267*15932Smckusick /* figure out what kind of node c is !! */ 268758Speter p->nl_flags |= NUSED; 269758Speter } 270758Speter o += p->value[0]; 271758Speter continue; 272758Speter default: 273758Speter panic("lval2"); 274758Speter } 275758Speter } 276758Speter if (f) { 2772071Smckusic if (bn == 0) 2782071Smckusic /* 2792071Smckusic * global variables are referenced through 2802071Smckusic * pointers on the stack 2812071Smckusic */ 282*15932Smckusick (void) put(2, PTR_RV | bn<<8+INDX, o); 2832071Smckusic else 284*15932Smckusick (void) put(2, O_LV | bn<<8+INDX, o); 285758Speter } else { 286758Speter if (o) { 287*15932Smckusick (void) put(2, O_OFF, o); 288758Speter } 289758Speter } 290758Speter return (p->type); 291758Speter bad: 292*15932Smckusick cerror("Error occurred on qualification of %s", var->var_node.cptr); 293*15932Smckusick return (NLNIL); 2942122Smckusic # endif OBJ 295758Speter } 296758Speter 297*15932Smckusick int lptr(c) 298*15932Smckusick register struct tnode *c; 299758Speter { 300*15932Smckusick register struct tnode *co; 301758Speter 302*15932Smckusick for (; c != TR_NIL; c = c->list_node.next) { 303*15932Smckusick co = c->list_node.list; 304*15932Smckusick if (co == TR_NIL) { 305758Speter return (NIL); 306758Speter } 307*15932Smckusick switch (co->tag) { 308758Speter 309758Speter case T_PTR: 310758Speter return (1); 311758Speter case T_ARGL: 312758Speter return (0); 313758Speter case T_ARY: 314758Speter case T_FIELD: 315758Speter continue; 316758Speter default: 317758Speter panic("lptr"); 318758Speter } 319758Speter } 320758Speter return (0); 321758Speter } 322758Speter 323758Speter /* 324758Speter * Arycod does the 325758Speter * code generation 326758Speter * for subscripting. 327758Speter */ 328*15932Smckusick int arycod(np, el) 329758Speter struct nl *np; 330*15932Smckusick struct tnode *el; 331758Speter { 332758Speter register struct nl *p, *ap; 3333890Smckusic long sub; 3343890Smckusic bool constsub; 335*15932Smckusick extern bool constval(); 336*15932Smckusick int i, d; /* v, v1; these aren't used */ 337758Speter int w; 338758Speter 339758Speter p = np; 340*15932Smckusick if (el == TR_NIL) { 341758Speter return (0); 342758Speter } 343758Speter d = p->value[0]; 344758Speter /* 345758Speter * Check each subscript 346758Speter */ 347758Speter for (i = 1; i <= d; i++) { 348*15932Smckusick if (el == TR_NIL) { 349*15932Smckusick error("Too few subscripts (%d given, %d required)", (char *) i-1, (char *) d); 350758Speter return (-1); 351758Speter } 352758Speter p = p->chain; 353*15932Smckusick if (constsub = constval(el->list_node.list)) { 3543890Smckusic ap = con.ctype; 3553890Smckusic sub = con.crval; 3563890Smckusic if (sub < p->range[0] || sub > p->range[1]) { 357*15932Smckusick error("Subscript value of %D is out of range", (char *) sub); 358758Speter return (0); 3593890Smckusic } 3603890Smckusic sub -= p->range[0]; 3613890Smckusic } else { 3623890Smckusic # ifdef PC 3633890Smckusic precheck( p , "_SUBSC" , "_SUBSCZ" ); 3643890Smckusic # endif PC 365*15932Smckusick ap = rvalue(el->list_node.list, NLNIL , RREQ ); 3663890Smckusic if (ap == NIL) { 3673890Smckusic return (0); 3683890Smckusic } 3693890Smckusic # ifdef PC 37010361Smckusick postcheck(p, ap); 37110361Smckusick sconv(p2type(ap),P2INT); 3723890Smckusic # endif PC 373758Speter } 374*15932Smckusick if (incompat(ap, p->type, el->list_node.list)) { 375758Speter cerror("Array index type incompatible with declared index type"); 376758Speter if (d != 1) { 377*15932Smckusick cerror("Error occurred on index number %d", (char *) i); 378758Speter } 379758Speter return (-1); 380758Speter } 381758Speter w = aryconst(np, i); 382758Speter # ifdef OBJ 3833890Smckusic if (constsub) { 3843890Smckusic sub *= w; 3853890Smckusic if (sub != 0) { 386*15932Smckusick w = width(ap); 387*15932Smckusick (void) put(2, w <= 2 ? O_CON2 : O_CON4, sub); 388*15932Smckusick (void) gen(NIL, T_ADD, sizeof(char *), w); 3893890Smckusic } 390*15932Smckusick el = el->list_node.next; 3913890Smckusic continue; 3923890Smckusic } 393758Speter if (opt('t') == 0) { 394758Speter switch (w) { 395758Speter case 8: 396758Speter w = 6; 397758Speter case 4: 398758Speter case 2: 399758Speter case 1: 400*15932Smckusick (void) put(2, (width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]); 401*15932Smckusick el = el->list_node.next; 402758Speter continue; 403758Speter } 404758Speter } 405*15932Smckusick (void) put(4, width(ap) != 4 ? O_INX2 : O_INX4, w, 4063074Smckusic (short)p->range[0], (short)(p->range[1])); 407*15932Smckusick el = el->list_node.next; 4083890Smckusic continue; 409758Speter # endif OBJ 410758Speter # ifdef PC 411758Speter /* 412758Speter * subtract off the lower bound 413758Speter */ 4143890Smckusic if (constsub) { 4153890Smckusic sub *= w; 4163890Smckusic if (sub != 0) { 417*15932Smckusick putleaf( P2ICON , (int) sub , 0 , P2INT , (char *) 0 ); 4183890Smckusic putop(P2PLUS, ADDTYPE(p2type(np->type), P2PTR)); 4193890Smckusic } 420*15932Smckusick el = el->list_node.next; 4213890Smckusic continue; 4223890Smckusic } 423758Speter if ( p -> range[ 0 ] != 0 ) { 424*15932Smckusick putleaf( P2ICON , (int) p -> range[0] , 0 , P2INT , (char *) 0 ); 425758Speter putop( P2MINUS , P2INT ); 426758Speter } 427758Speter /* 428758Speter * multiply by the width of the elements 429758Speter */ 430758Speter if ( w != 1 ) { 431*15932Smckusick putleaf( P2ICON , w , 0 , P2INT , (char *) 0 ); 432758Speter putop( P2MUL , P2INT ); 433758Speter } 434758Speter /* 435758Speter * and add it to the base address 436758Speter */ 437758Speter putop( P2PLUS , ADDTYPE( p2type( np -> type ) , P2PTR ) ); 438*15932Smckusick el = el->list_node.next; 439758Speter # endif PC 440758Speter } 441*15932Smckusick if (el != TR_NIL) { 442758Speter do { 443*15932Smckusick el = el->list_node.next; 444758Speter i++; 445*15932Smckusick } while (el != TR_NIL); 446*15932Smckusick error("Too many subscripts (%d given, %d required)", (char *) (i-1), (char *) d); 447758Speter return (-1); 448758Speter } 449758Speter return (1); 450758Speter } 451