1*48116Sbostic /*- 2*48116Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*48116Sbostic * All rights reserved. 4*48116Sbostic * 5*48116Sbostic * %sccs.include.redist.c% 622175Sdist */ 7758Speter 815932Smckusick #ifndef lint 9*48116Sbostic static char sccsid[] = "@(#)lval.c 5.3 (Berkeley) 04/16/91"; 10*48116Sbostic #endif /* not lint */ 11758Speter 12758Speter #include "whoami.h" 13758Speter #include "0.h" 14758Speter #include "tree.h" 15758Speter #include "opcode.h" 16758Speter #include "objfmt.h" 1715932Smckusick #include "tree_ty.h" 18758Speter #ifdef PC 19758Speter # include "pc.h" 2018461Sralph # include <pcc.h> 21758Speter #endif PC 22758Speter 23758Speter extern int flagwas; 24758Speter /* 25758Speter * Lvalue computes the address 26758Speter * of a qualified name and 27758Speter * leaves it on the stack. 28758Speter * for pc, it can be asked for either an lvalue or an rvalue. 29758Speter * the semantics are the same, only the code is different. 30758Speter */ 3115932Smckusick /*ARGSUSED*/ 32758Speter struct nl * 3315932Smckusick lvalue(var, modflag , required ) 3415932Smckusick struct tnode *var; 3515932Smckusick int modflag; 36758Speter int required; 37758Speter { 3815932Smckusick #ifdef OBJ 39758Speter register struct nl *p; 40758Speter struct nl *firstp, *lastp; 4115932Smckusick register struct tnode *c, *co; 4215967Smckusick int f, o, s; 43758Speter /* 44758Speter * Note that the local optimizations 45758Speter * done here for offsets would more 46758Speter * appropriately be done in put. 47758Speter */ 4815932Smckusick struct tnode tr; /* T_FIELD */ 4915932Smckusick struct tnode *tr_ptr; 5015932Smckusick struct tnode l_node; 5115932Smckusick #endif 52758Speter 5315932Smckusick if (var == TR_NIL) { 5415932Smckusick return (NLNIL); 55758Speter } 5615932Smckusick if (nowexp(var)) { 5715932Smckusick return (NLNIL); 58758Speter } 5915932Smckusick if (var->tag != T_VAR) { 60758Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 6115932Smckusick return (NLNIL); 62758Speter } 63758Speter # ifdef PC 64758Speter /* 65758Speter * pc requires a whole different control flow 66758Speter */ 6715932Smckusick return pclvalue( var , modflag , required ); 68758Speter # endif PC 692122Smckusic # ifdef OBJ 702122Smckusic /* 712122Smckusic * pi uses the rest of the function 722122Smckusic */ 7315932Smckusick firstp = p = lookup(var->var_node.cptr); 7415932Smckusick if (p == NLNIL) { 7515932Smckusick return (NLNIL); 76758Speter } 7715932Smckusick c = var->var_node.qual; 78758Speter if ((modflag & NOUSE) && !lptr(c)) { 79758Speter p->nl_flags = flagwas; 80758Speter } 81758Speter if (modflag & MOD) { 82758Speter p->nl_flags |= NMOD; 83758Speter } 84758Speter /* 85758Speter * Only possibilities for p->class here 86758Speter * are the named classes, i.e. CONST, TYPE 87758Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 88758Speter */ 8915932Smckusick tr_ptr = &l_node; 90758Speter switch (p->class) { 91758Speter case WITHPTR: 92758Speter /* 93758Speter * Construct the tree implied by 94758Speter * the with statement 95758Speter */ 9615932Smckusick l_node.tag = T_LISTPP; 9715932Smckusick 9815932Smckusick /* the cast has got to go but until the node is figured 9915932Smckusick out it stays */ 10015932Smckusick 10115932Smckusick tr_ptr->list_node.list = (&tr); 10215932Smckusick tr_ptr->list_node.next = var->var_node.qual; 10315932Smckusick tr.tag = T_FIELD; 10415932Smckusick tr.field_node.id_ptr = var->var_node.cptr; 10515932Smckusick c = tr_ptr; /* c is a ptr to a tnode */ 106758Speter # ifdef PTREE 107758Speter /* 10815932Smckusick * mung var->fields to say which field this T_VAR is 109758Speter * for VarCopy 110758Speter */ 11115932Smckusick 11215932Smckusick /* problem! reclook returns struct nl* */ 11315932Smckusick 11415932Smckusick var->var_node.fields = reclook( p -> type , 11515932Smckusick var->var_node.line_no ); 116758Speter # endif 117758Speter /* and fall through */ 118758Speter case REF: 119758Speter /* 120758Speter * Obtain the indirect word 121758Speter * of the WITHPTR or REF 122758Speter * as the base of our lvalue 123758Speter */ 12415932Smckusick (void) put(2, PTR_RV | bn << 8+INDX , (int)p->value[0] ); 125758Speter f = 0; /* have an lv on stack */ 126758Speter o = 0; 127758Speter break; 128758Speter case VAR: 12915967Smckusick if (p->type->class != CRANGE) { 13015967Smckusick f = 1; /* no lv on stack yet */ 13115967Smckusick o = p->value[0]; 13215967Smckusick } else { 13315967Smckusick error("Conformant array bound %s found where variable required", p->symbol); 13415967Smckusick return(NLNIL); 13515967Smckusick } 136758Speter break; 137758Speter default: 138758Speter error("%s %s found where variable required", classes[p->class], p->symbol); 13915932Smckusick return (NLNIL); 140758Speter } 141758Speter /* 142758Speter * Loop and handle each 143758Speter * qualification on the name 144758Speter */ 14515932Smckusick if (c == TR_NIL && (modflag&ASGN) && ( p->value[NL_FORV] & FORVAR ) ) { 146758Speter error("Can't modify the for variable %s in the range of the loop", p->symbol); 14715932Smckusick return (NLNIL); 148758Speter } 14915967Smckusick s = 0; /* subscripts seen */ 15015932Smckusick for (; c != TR_NIL; c = c->list_node.next) { 15115932Smckusick co = c->list_node.list; /* co is a ptr to a tnode */ 15215932Smckusick if (co == TR_NIL) { 15315932Smckusick return (NLNIL); 154758Speter } 155758Speter lastp = p; 156758Speter p = p->type; 15715932Smckusick if (p == NLNIL) { 15815932Smckusick return (NLNIL); 159758Speter } 16015967Smckusick /* 16115967Smckusick * If we haven't seen enough subscripts, and the next 16215967Smckusick * qualification isn't array reference, then it's an error. 16315967Smckusick */ 16415967Smckusick if (s && co->tag != T_ARY) { 16515967Smckusick error("Too few subscripts (%d given, %d required)", 16615967Smckusick s, p->value[0]); 16715967Smckusick } 16815932Smckusick switch (co->tag) { 169758Speter case T_PTR: 170758Speter /* 171758Speter * Pointer qualification. 172758Speter */ 173758Speter lastp->nl_flags |= NUSED; 174758Speter if (p->class != PTR && p->class != FILET) { 175758Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 176758Speter goto bad; 177758Speter } 178758Speter if (f) { 1792071Smckusic if (p->class == FILET && bn != 0) 18015932Smckusick (void) put(2, O_LV | bn <<8+INDX , o ); 1812071Smckusic else 1822071Smckusic /* 1832071Smckusic * this is the indirection from 1842071Smckusic * the address of the pointer 1852071Smckusic * to the pointer itself. 1862071Smckusic * kirk sez: 1872071Smckusic * fnil doesn't want this. 1882071Smckusic * and does it itself for files 1892071Smckusic * since only it knows where the 1902071Smckusic * actual window is. 1912071Smckusic * but i have to do this for 1922071Smckusic * regular pointers. 1932071Smckusic * This is further complicated by 1942071Smckusic * the fact that global variables 1952071Smckusic * are referenced through pointers 1962071Smckusic * on the stack. Thus an RV on a 1972071Smckusic * global variable is the same as 1982071Smckusic * an LV of a non-global one ?!? 1992071Smckusic */ 20015932Smckusick (void) put(2, PTR_RV | bn <<8+INDX , o ); 201758Speter } else { 202758Speter if (o) { 20315932Smckusick (void) put(2, O_OFF, o); 204758Speter } 2052104Smckusic if (p->class != FILET || bn == 0) 20615932Smckusick (void) put(1, PTR_IND); 207758Speter } 208758Speter /* 209758Speter * Pointer cannot be 210758Speter * nil and file cannot 211758Speter * be at end-of-file. 212758Speter */ 21315932Smckusick (void) put(1, p->class == FILET ? O_FNIL : O_NIL); 214758Speter f = o = 0; 215758Speter continue; 216758Speter case T_ARGL: 217758Speter if (p->class != ARRAY) { 218758Speter if (lastp == firstp) { 21915932Smckusick error("%s is a %s, not a function", var->var_node.cptr, classes[firstp->class]); 220758Speter } else { 221758Speter error("Illegal function qualificiation"); 222758Speter } 22315932Smckusick return (NLNIL); 224758Speter } 225758Speter recovered(); 226758Speter error("Pascal uses [] for subscripting, not ()"); 227758Speter case T_ARY: 228758Speter if (p->class != ARRAY) { 229758Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 230758Speter goto bad; 231758Speter } 232758Speter if (f) { 2332071Smckusic if (bn == 0) 2342071Smckusic /* 2352071Smckusic * global variables are 2362071Smckusic * referenced through pointers 2372071Smckusic * on the stack 2382071Smckusic */ 23915932Smckusick (void) put(2, PTR_RV | bn<<8+INDX, o); 2402071Smckusic else 24115932Smckusick (void) put(2, O_LV | bn<<8+INDX, o); 242758Speter } else { 243758Speter if (o) { 24415932Smckusick (void) put(2, O_OFF, o); 245758Speter } 246758Speter } 24715967Smckusick switch(s = arycod(p,co->ary_node.expr_list,s)) { 24815967Smckusick /* 24915967Smckusick * This is the number of subscripts seen 25015967Smckusick */ 251758Speter case 0: 25215932Smckusick return (NLNIL); 253758Speter case -1: 254758Speter goto bad; 255758Speter } 25615967Smckusick if (s == p->value[0]) { 25715967Smckusick s = 0; 25815967Smckusick } else { 25915967Smckusick p = lastp; 26015967Smckusick } 261758Speter f = o = 0; 262758Speter continue; 263758Speter case T_FIELD: 264758Speter /* 265758Speter * Field names are just 266758Speter * an offset with some 267758Speter * semantic checking. 268758Speter */ 269758Speter if (p->class != RECORD) { 270758Speter error(". allowed only on records, not on %ss", nameof(p)); 271758Speter goto bad; 272758Speter } 27315932Smckusick /* must define the field node!! */ 27415932Smckusick if (co->field_node.id_ptr == NIL) { 27515932Smckusick return (NLNIL); 276758Speter } 27715932Smckusick p = reclook(p, co->field_node.id_ptr); 27815932Smckusick if (p == NLNIL) { 27915932Smckusick error("%s is not a field in this record", co->field_node.id_ptr); 280758Speter goto bad; 281758Speter } 282758Speter # ifdef PTREE 283758Speter /* 284758Speter * mung co[3] to indicate which field 285758Speter * this is for SelCopy 286758Speter */ 28715932Smckusick co->field_node.nl_entry = p; 288758Speter # endif 289758Speter if (modflag & MOD) { 290758Speter p->nl_flags |= NMOD; 291758Speter } 29215932Smckusick if ((modflag & NOUSE) == 0 || 29315932Smckusick lptr(c->list_node.next)) { 29415932Smckusick /* figure out what kind of node c is !! */ 295758Speter p->nl_flags |= NUSED; 296758Speter } 297758Speter o += p->value[0]; 298758Speter continue; 299758Speter default: 300758Speter panic("lval2"); 301758Speter } 302758Speter } 30315967Smckusick if (s) { 30415967Smckusick error("Too few subscripts (%d given, %d required)", 30515967Smckusick s, p->type->value[0]); 30615986Saoki return NLNIL; 30715967Smckusick } 308758Speter if (f) { 3092071Smckusic if (bn == 0) 3102071Smckusic /* 3112071Smckusic * global variables are referenced through 3122071Smckusic * pointers on the stack 3132071Smckusic */ 31415932Smckusick (void) put(2, PTR_RV | bn<<8+INDX, o); 3152071Smckusic else 31615932Smckusick (void) put(2, O_LV | bn<<8+INDX, o); 317758Speter } else { 318758Speter if (o) { 31915932Smckusick (void) put(2, O_OFF, o); 320758Speter } 321758Speter } 322758Speter return (p->type); 323758Speter bad: 32415932Smckusick cerror("Error occurred on qualification of %s", var->var_node.cptr); 32515932Smckusick return (NLNIL); 3262122Smckusic # endif OBJ 327758Speter } 328758Speter 32915932Smckusick int lptr(c) 33015932Smckusick register struct tnode *c; 331758Speter { 33215932Smckusick register struct tnode *co; 333758Speter 33415932Smckusick for (; c != TR_NIL; c = c->list_node.next) { 33515932Smckusick co = c->list_node.list; 33615932Smckusick if (co == TR_NIL) { 337758Speter return (NIL); 338758Speter } 33915932Smckusick switch (co->tag) { 340758Speter 341758Speter case T_PTR: 342758Speter return (1); 343758Speter case T_ARGL: 344758Speter return (0); 345758Speter case T_ARY: 346758Speter case T_FIELD: 347758Speter continue; 348758Speter default: 349758Speter panic("lptr"); 350758Speter } 351758Speter } 352758Speter return (0); 353758Speter } 354758Speter 355758Speter /* 356758Speter * Arycod does the 357758Speter * code generation 358758Speter * for subscripting. 35915967Smckusick * n is the number of 36015967Smckusick * subscripts already seen 36115967Smckusick * (CLN 09/13/83) 362758Speter */ 36315967Smckusick int arycod(np, el, n) 364758Speter struct nl *np; 36515932Smckusick struct tnode *el; 36615967Smckusick int n; 367758Speter { 368758Speter register struct nl *p, *ap; 3693890Smckusic long sub; 3703890Smckusic bool constsub; 37115932Smckusick extern bool constval(); 37215932Smckusick int i, d; /* v, v1; these aren't used */ 373758Speter int w; 374758Speter 375758Speter p = np; 37615932Smckusick if (el == TR_NIL) { 377758Speter return (0); 378758Speter } 379758Speter d = p->value[0]; 38015967Smckusick for (i = 1; i <= n; i++) { 38115967Smckusick p = p->chain; 38215967Smckusick } 383758Speter /* 384758Speter * Check each subscript 385758Speter */ 38615967Smckusick for (i = n+1; i <= d; i++) { 38715932Smckusick if (el == TR_NIL) { 38815967Smckusick return (i-1); 389758Speter } 390758Speter p = p->chain; 39124052Smckusick if (p == NLNIL) 39224052Smckusick return (0); 39315967Smckusick if ((p->class != CRANGE) && 39415967Smckusick (constsub = constval(el->list_node.list))) { 3953890Smckusic ap = con.ctype; 3963890Smckusic sub = con.crval; 3973890Smckusic if (sub < p->range[0] || sub > p->range[1]) { 39815932Smckusick error("Subscript value of %D is out of range", (char *) sub); 399758Speter return (0); 4003890Smckusic } 4013890Smckusic sub -= p->range[0]; 4023890Smckusic } else { 4033890Smckusic # ifdef PC 4043890Smckusic precheck( p , "_SUBSC" , "_SUBSCZ" ); 4053890Smckusic # endif PC 40615932Smckusick ap = rvalue(el->list_node.list, NLNIL , RREQ ); 4073890Smckusic if (ap == NIL) { 4083890Smckusic return (0); 4093890Smckusic } 4103890Smckusic # ifdef PC 41110361Smckusick postcheck(p, ap); 41218461Sralph sconv(p2type(ap),PCCT_INT); 4133890Smckusic # endif PC 414758Speter } 41515932Smckusick if (incompat(ap, p->type, el->list_node.list)) { 416758Speter cerror("Array index type incompatible with declared index type"); 417758Speter if (d != 1) { 41815932Smckusick cerror("Error occurred on index number %d", (char *) i); 419758Speter } 420758Speter return (-1); 421758Speter } 42215967Smckusick if (p->class == CRANGE) { 42315986Saoki constsub = FALSE; 42415967Smckusick } else { 42515967Smckusick w = aryconst(np, i); 42615967Smckusick } 427758Speter # ifdef OBJ 4283890Smckusic if (constsub) { 4293890Smckusic sub *= w; 4303890Smckusic if (sub != 0) { 43115933Smckusick w = bytes(sub, sub); 43215932Smckusick (void) put(2, w <= 2 ? O_CON2 : O_CON4, sub); 43315932Smckusick (void) gen(NIL, T_ADD, sizeof(char *), w); 4343890Smckusic } 43515932Smckusick el = el->list_node.next; 4363890Smckusic continue; 4373890Smckusic } 43815967Smckusick if (p->class == CRANGE) { 43915967Smckusick putcbnds(p, 0); 44015967Smckusick putcbnds(p, 1); 44115967Smckusick putcbnds(p, 2); 44215967Smckusick } else if (opt('t') == 0) { 443758Speter switch (w) { 444758Speter case 8: 445758Speter w = 6; 446758Speter case 4: 447758Speter case 2: 448758Speter case 1: 44915932Smckusick (void) put(2, (width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]); 45015932Smckusick el = el->list_node.next; 451758Speter continue; 452758Speter } 453758Speter } 45415967Smckusick if (p->class == CRANGE) { 45515967Smckusick if (width(p) == 4) { 45615967Smckusick put(1, width(ap) != 4 ? O_VINX42 : O_VINX4); 45715967Smckusick } else { 45815967Smckusick put(1, width(ap) != 4 ? O_VINX2 : O_VINX24); 45915967Smckusick } 46015967Smckusick } else { 46115967Smckusick put(4, width(ap) != 4 ? O_INX2 : O_INX4, w, 46215967Smckusick (short)p->range[0], (short)(p->range[1])); 46315967Smckusick } 46415932Smckusick el = el->list_node.next; 4653890Smckusic continue; 466758Speter # endif OBJ 467758Speter # ifdef PC 468758Speter /* 469758Speter * subtract off the lower bound 470758Speter */ 4713890Smckusic if (constsub) { 4723890Smckusic sub *= w; 4733890Smckusic if (sub != 0) { 47418461Sralph putleaf( PCC_ICON , (int) sub , 0 , PCCT_INT , (char *) 0 ); 47518461Sralph putop(PCC_PLUS, PCCM_ADDTYPE(p2type(np->type), PCCTM_PTR)); 4763890Smckusic } 47715932Smckusick el = el->list_node.next; 4783890Smckusic continue; 4793890Smckusic } 48015967Smckusick if (p->class == CRANGE) { 481758Speter /* 48215967Smckusick * if conformant array, subtract off lower bound 483758Speter */ 48415967Smckusick ap = p->nptr[0]; 48515967Smckusick putRV(ap->symbol, (ap->nl_block & 037), ap->value[0], 48615967Smckusick ap->extra_flags, p2type( ap ) ); 48718461Sralph putop( PCC_MINUS, PCCT_INT ); 48815967Smckusick /* 48915967Smckusick * and multiply by the width of the elements 49015967Smckusick */ 49115967Smckusick ap = p->nptr[2]; 49215967Smckusick putRV( 0 , (ap->nl_block & 037), ap->value[0], 49315967Smckusick ap->extra_flags, p2type( ap ) ); 49418461Sralph putop( PCC_MUL , PCCT_INT ); 49515967Smckusick } else { 49615967Smckusick if ( p -> range[ 0 ] != 0 ) { 49718461Sralph putleaf( PCC_ICON , (int) p -> range[0] , 0 , PCCT_INT , (char *) 0 ); 49818461Sralph putop( PCC_MINUS , PCCT_INT ); 49915967Smckusick } 50015967Smckusick /* 50115967Smckusick * multiply by the width of the elements 50215967Smckusick */ 50315967Smckusick if ( w != 1 ) { 50418461Sralph putleaf( PCC_ICON , w , 0 , PCCT_INT , (char *) 0 ); 50518461Sralph putop( PCC_MUL , PCCT_INT ); 50615967Smckusick } 507758Speter } 508758Speter /* 509758Speter * and add it to the base address 510758Speter */ 51118461Sralph putop( PCC_PLUS , PCCM_ADDTYPE( p2type( np -> type ) , PCCTM_PTR ) ); 51215932Smckusick el = el->list_node.next; 513758Speter # endif PC 514758Speter } 51515932Smckusick if (el != TR_NIL) { 51615967Smckusick if (np->type->class != ARRAY) { 517758Speter do { 51815932Smckusick el = el->list_node.next; 519758Speter i++; 52015932Smckusick } while (el != TR_NIL); 52115932Smckusick error("Too many subscripts (%d given, %d required)", (char *) (i-1), (char *) d); 522758Speter return (-1); 52315967Smckusick } else { 52415967Smckusick return(arycod(np->type, el, d)); 52515967Smckusick } 526758Speter } 52715967Smckusick return (d); 528758Speter } 52915967Smckusick 53015967Smckusick #ifdef OBJ 53115967Smckusick /* 53215967Smckusick * Put out the conformant array bounds (lower bound, upper bound or width) 53315967Smckusick * for conformant array type ctype. 53415967Smckusick * The value of i determines which is being put 53515967Smckusick * i = 0: lower bound, i=1: upper bound, i=2: width 53615967Smckusick */ 53715967Smckusick putcbnds(ctype, i) 53815967Smckusick struct nl *ctype; 53915967Smckusick int i; 54015967Smckusick { 54115967Smckusick switch(width(ctype->type)) { 54215967Smckusick case 1: 54315967Smckusick put(2, O_RV1 | (ctype->nl_block & 037) << 8+INDX, 54415967Smckusick (int)ctype->nptr[i]->value[0]); 54515967Smckusick break; 54615967Smckusick case 2: 54715967Smckusick put(2, O_RV2 | (ctype->nl_block & 037) << 8+INDX, 54815967Smckusick (int)ctype->nptr[i]->value[0]); 54915967Smckusick break; 55015967Smckusick case 4: 55115967Smckusick default: 55215967Smckusick put(2, O_RV4 | (ctype->nl_block & 037) << 8+INDX, 55315967Smckusick (int)ctype->nptr[i]->value[0]); 55415967Smckusick } 55515967Smckusick } 55615967Smckusick #endif OBJ 557