1*22175Sdist /* 2*22175Sdist * Copyright (c) 1980 Regents of the University of California. 3*22175Sdist * All rights reserved. The Berkeley software License Agreement 4*22175Sdist * specifies the terms and conditions for redistribution. 5*22175Sdist */ 6758Speter 715932Smckusick #ifndef lint 8*22175Sdist static char sccsid[] = "@(#)lval.c 5.1 (Berkeley) 06/05/85"; 9*22175Sdist #endif not lint 10758Speter 11758Speter #include "whoami.h" 12758Speter #include "0.h" 13758Speter #include "tree.h" 14758Speter #include "opcode.h" 15758Speter #include "objfmt.h" 1615932Smckusick #include "tree_ty.h" 17758Speter #ifdef PC 18758Speter # include "pc.h" 1918461Sralph # include <pcc.h> 20758Speter #endif PC 21758Speter 22758Speter extern int flagwas; 23758Speter /* 24758Speter * Lvalue computes the address 25758Speter * of a qualified name and 26758Speter * leaves it on the stack. 27758Speter * for pc, it can be asked for either an lvalue or an rvalue. 28758Speter * the semantics are the same, only the code is different. 29758Speter */ 3015932Smckusick /*ARGSUSED*/ 31758Speter struct nl * 3215932Smckusick lvalue(var, modflag , required ) 3315932Smckusick struct tnode *var; 3415932Smckusick int modflag; 35758Speter int required; 36758Speter { 3715932Smckusick #ifdef OBJ 38758Speter register struct nl *p; 39758Speter struct nl *firstp, *lastp; 4015932Smckusick register struct tnode *c, *co; 4115967Smckusick int f, o, s; 42758Speter /* 43758Speter * Note that the local optimizations 44758Speter * done here for offsets would more 45758Speter * appropriately be done in put. 46758Speter */ 4715932Smckusick struct tnode tr; /* T_FIELD */ 4815932Smckusick struct tnode *tr_ptr; 4915932Smckusick struct tnode l_node; 5015932Smckusick #endif 51758Speter 5215932Smckusick if (var == TR_NIL) { 5315932Smckusick return (NLNIL); 54758Speter } 5515932Smckusick if (nowexp(var)) { 5615932Smckusick return (NLNIL); 57758Speter } 5815932Smckusick if (var->tag != T_VAR) { 59758Speter error("Variable required"); /* Pass mesgs down from pt of call ? */ 6015932Smckusick return (NLNIL); 61758Speter } 62758Speter # ifdef PC 63758Speter /* 64758Speter * pc requires a whole different control flow 65758Speter */ 6615932Smckusick return pclvalue( var , modflag , required ); 67758Speter # endif PC 682122Smckusic # ifdef OBJ 692122Smckusic /* 702122Smckusic * pi uses the rest of the function 712122Smckusic */ 7215932Smckusick firstp = p = lookup(var->var_node.cptr); 7315932Smckusick if (p == NLNIL) { 7415932Smckusick return (NLNIL); 75758Speter } 7615932Smckusick c = var->var_node.qual; 77758Speter if ((modflag & NOUSE) && !lptr(c)) { 78758Speter p->nl_flags = flagwas; 79758Speter } 80758Speter if (modflag & MOD) { 81758Speter p->nl_flags |= NMOD; 82758Speter } 83758Speter /* 84758Speter * Only possibilities for p->class here 85758Speter * are the named classes, i.e. CONST, TYPE 86758Speter * VAR, PROC, FUNC, REF, or a WITHPTR. 87758Speter */ 8815932Smckusick tr_ptr = &l_node; 89758Speter switch (p->class) { 90758Speter case WITHPTR: 91758Speter /* 92758Speter * Construct the tree implied by 93758Speter * the with statement 94758Speter */ 9515932Smckusick l_node.tag = T_LISTPP; 9615932Smckusick 9715932Smckusick /* the cast has got to go but until the node is figured 9815932Smckusick out it stays */ 9915932Smckusick 10015932Smckusick tr_ptr->list_node.list = (&tr); 10115932Smckusick tr_ptr->list_node.next = var->var_node.qual; 10215932Smckusick tr.tag = T_FIELD; 10315932Smckusick tr.field_node.id_ptr = var->var_node.cptr; 10415932Smckusick c = tr_ptr; /* c is a ptr to a tnode */ 105758Speter # ifdef PTREE 106758Speter /* 10715932Smckusick * mung var->fields to say which field this T_VAR is 108758Speter * for VarCopy 109758Speter */ 11015932Smckusick 11115932Smckusick /* problem! reclook returns struct nl* */ 11215932Smckusick 11315932Smckusick var->var_node.fields = reclook( p -> type , 11415932Smckusick var->var_node.line_no ); 115758Speter # endif 116758Speter /* and fall through */ 117758Speter case REF: 118758Speter /* 119758Speter * Obtain the indirect word 120758Speter * of the WITHPTR or REF 121758Speter * as the base of our lvalue 122758Speter */ 12315932Smckusick (void) put(2, PTR_RV | bn << 8+INDX , (int)p->value[0] ); 124758Speter f = 0; /* have an lv on stack */ 125758Speter o = 0; 126758Speter break; 127758Speter case VAR: 12815967Smckusick if (p->type->class != CRANGE) { 12915967Smckusick f = 1; /* no lv on stack yet */ 13015967Smckusick o = p->value[0]; 13115967Smckusick } else { 13215967Smckusick error("Conformant array bound %s found where variable required", p->symbol); 13315967Smckusick return(NLNIL); 13415967Smckusick } 135758Speter break; 136758Speter default: 137758Speter error("%s %s found where variable required", classes[p->class], p->symbol); 13815932Smckusick return (NLNIL); 139758Speter } 140758Speter /* 141758Speter * Loop and handle each 142758Speter * qualification on the name 143758Speter */ 14415932Smckusick if (c == TR_NIL && (modflag&ASGN) && ( p->value[NL_FORV] & FORVAR ) ) { 145758Speter error("Can't modify the for variable %s in the range of the loop", p->symbol); 14615932Smckusick return (NLNIL); 147758Speter } 14815967Smckusick s = 0; /* subscripts seen */ 14915932Smckusick for (; c != TR_NIL; c = c->list_node.next) { 15015932Smckusick co = c->list_node.list; /* co is a ptr to a tnode */ 15115932Smckusick if (co == TR_NIL) { 15215932Smckusick return (NLNIL); 153758Speter } 154758Speter lastp = p; 155758Speter p = p->type; 15615932Smckusick if (p == NLNIL) { 15715932Smckusick return (NLNIL); 158758Speter } 15915967Smckusick /* 16015967Smckusick * If we haven't seen enough subscripts, and the next 16115967Smckusick * qualification isn't array reference, then it's an error. 16215967Smckusick */ 16315967Smckusick if (s && co->tag != T_ARY) { 16415967Smckusick error("Too few subscripts (%d given, %d required)", 16515967Smckusick s, p->value[0]); 16615967Smckusick } 16715932Smckusick switch (co->tag) { 168758Speter case T_PTR: 169758Speter /* 170758Speter * Pointer qualification. 171758Speter */ 172758Speter lastp->nl_flags |= NUSED; 173758Speter if (p->class != PTR && p->class != FILET) { 174758Speter error("^ allowed only on files and pointers, not on %ss", nameof(p)); 175758Speter goto bad; 176758Speter } 177758Speter if (f) { 1782071Smckusic if (p->class == FILET && bn != 0) 17915932Smckusick (void) put(2, O_LV | bn <<8+INDX , o ); 1802071Smckusic else 1812071Smckusic /* 1822071Smckusic * this is the indirection from 1832071Smckusic * the address of the pointer 1842071Smckusic * to the pointer itself. 1852071Smckusic * kirk sez: 1862071Smckusic * fnil doesn't want this. 1872071Smckusic * and does it itself for files 1882071Smckusic * since only it knows where the 1892071Smckusic * actual window is. 1902071Smckusic * but i have to do this for 1912071Smckusic * regular pointers. 1922071Smckusic * This is further complicated by 1932071Smckusic * the fact that global variables 1942071Smckusic * are referenced through pointers 1952071Smckusic * on the stack. Thus an RV on a 1962071Smckusic * global variable is the same as 1972071Smckusic * an LV of a non-global one ?!? 1982071Smckusic */ 19915932Smckusick (void) put(2, PTR_RV | bn <<8+INDX , o ); 200758Speter } else { 201758Speter if (o) { 20215932Smckusick (void) put(2, O_OFF, o); 203758Speter } 2042104Smckusic if (p->class != FILET || bn == 0) 20515932Smckusick (void) put(1, PTR_IND); 206758Speter } 207758Speter /* 208758Speter * Pointer cannot be 209758Speter * nil and file cannot 210758Speter * be at end-of-file. 211758Speter */ 21215932Smckusick (void) put(1, p->class == FILET ? O_FNIL : O_NIL); 213758Speter f = o = 0; 214758Speter continue; 215758Speter case T_ARGL: 216758Speter if (p->class != ARRAY) { 217758Speter if (lastp == firstp) { 21815932Smckusick error("%s is a %s, not a function", var->var_node.cptr, classes[firstp->class]); 219758Speter } else { 220758Speter error("Illegal function qualificiation"); 221758Speter } 22215932Smckusick return (NLNIL); 223758Speter } 224758Speter recovered(); 225758Speter error("Pascal uses [] for subscripting, not ()"); 226758Speter case T_ARY: 227758Speter if (p->class != ARRAY) { 228758Speter error("Subscripting allowed only on arrays, not on %ss", nameof(p)); 229758Speter goto bad; 230758Speter } 231758Speter if (f) { 2322071Smckusic if (bn == 0) 2332071Smckusic /* 2342071Smckusic * global variables are 2352071Smckusic * referenced through pointers 2362071Smckusic * on the stack 2372071Smckusic */ 23815932Smckusick (void) put(2, PTR_RV | bn<<8+INDX, o); 2392071Smckusic else 24015932Smckusick (void) put(2, O_LV | bn<<8+INDX, o); 241758Speter } else { 242758Speter if (o) { 24315932Smckusick (void) put(2, O_OFF, o); 244758Speter } 245758Speter } 24615967Smckusick switch(s = arycod(p,co->ary_node.expr_list,s)) { 24715967Smckusick /* 24815967Smckusick * This is the number of subscripts seen 24915967Smckusick */ 250758Speter case 0: 25115932Smckusick return (NLNIL); 252758Speter case -1: 253758Speter goto bad; 254758Speter } 25515967Smckusick if (s == p->value[0]) { 25615967Smckusick s = 0; 25715967Smckusick } else { 25815967Smckusick p = lastp; 25915967Smckusick } 260758Speter f = o = 0; 261758Speter continue; 262758Speter case T_FIELD: 263758Speter /* 264758Speter * Field names are just 265758Speter * an offset with some 266758Speter * semantic checking. 267758Speter */ 268758Speter if (p->class != RECORD) { 269758Speter error(". allowed only on records, not on %ss", nameof(p)); 270758Speter goto bad; 271758Speter } 27215932Smckusick /* must define the field node!! */ 27315932Smckusick if (co->field_node.id_ptr == NIL) { 27415932Smckusick return (NLNIL); 275758Speter } 27615932Smckusick p = reclook(p, co->field_node.id_ptr); 27715932Smckusick if (p == NLNIL) { 27815932Smckusick error("%s is not a field in this record", co->field_node.id_ptr); 279758Speter goto bad; 280758Speter } 281758Speter # ifdef PTREE 282758Speter /* 283758Speter * mung co[3] to indicate which field 284758Speter * this is for SelCopy 285758Speter */ 28615932Smckusick co->field_node.nl_entry = p; 287758Speter # endif 288758Speter if (modflag & MOD) { 289758Speter p->nl_flags |= NMOD; 290758Speter } 29115932Smckusick if ((modflag & NOUSE) == 0 || 29215932Smckusick lptr(c->list_node.next)) { 29315932Smckusick /* figure out what kind of node c is !! */ 294758Speter p->nl_flags |= NUSED; 295758Speter } 296758Speter o += p->value[0]; 297758Speter continue; 298758Speter default: 299758Speter panic("lval2"); 300758Speter } 301758Speter } 30215967Smckusick if (s) { 30315967Smckusick error("Too few subscripts (%d given, %d required)", 30415967Smckusick s, p->type->value[0]); 30515986Saoki return NLNIL; 30615967Smckusick } 307758Speter if (f) { 3082071Smckusic if (bn == 0) 3092071Smckusic /* 3102071Smckusic * global variables are referenced through 3112071Smckusic * pointers on the stack 3122071Smckusic */ 31315932Smckusick (void) put(2, PTR_RV | bn<<8+INDX, o); 3142071Smckusic else 31515932Smckusick (void) put(2, O_LV | bn<<8+INDX, o); 316758Speter } else { 317758Speter if (o) { 31815932Smckusick (void) put(2, O_OFF, o); 319758Speter } 320758Speter } 321758Speter return (p->type); 322758Speter bad: 32315932Smckusick cerror("Error occurred on qualification of %s", var->var_node.cptr); 32415932Smckusick return (NLNIL); 3252122Smckusic # endif OBJ 326758Speter } 327758Speter 32815932Smckusick int lptr(c) 32915932Smckusick register struct tnode *c; 330758Speter { 33115932Smckusick register struct tnode *co; 332758Speter 33315932Smckusick for (; c != TR_NIL; c = c->list_node.next) { 33415932Smckusick co = c->list_node.list; 33515932Smckusick if (co == TR_NIL) { 336758Speter return (NIL); 337758Speter } 33815932Smckusick switch (co->tag) { 339758Speter 340758Speter case T_PTR: 341758Speter return (1); 342758Speter case T_ARGL: 343758Speter return (0); 344758Speter case T_ARY: 345758Speter case T_FIELD: 346758Speter continue; 347758Speter default: 348758Speter panic("lptr"); 349758Speter } 350758Speter } 351758Speter return (0); 352758Speter } 353758Speter 354758Speter /* 355758Speter * Arycod does the 356758Speter * code generation 357758Speter * for subscripting. 35815967Smckusick * n is the number of 35915967Smckusick * subscripts already seen 36015967Smckusick * (CLN 09/13/83) 361758Speter */ 36215967Smckusick int arycod(np, el, n) 363758Speter struct nl *np; 36415932Smckusick struct tnode *el; 36515967Smckusick int n; 366758Speter { 367758Speter register struct nl *p, *ap; 3683890Smckusic long sub; 3693890Smckusic bool constsub; 37015932Smckusick extern bool constval(); 37115932Smckusick int i, d; /* v, v1; these aren't used */ 372758Speter int w; 373758Speter 374758Speter p = np; 37515932Smckusick if (el == TR_NIL) { 376758Speter return (0); 377758Speter } 378758Speter d = p->value[0]; 37915967Smckusick for (i = 1; i <= n; i++) { 38015967Smckusick p = p->chain; 38115967Smckusick } 382758Speter /* 383758Speter * Check each subscript 384758Speter */ 38515967Smckusick for (i = n+1; i <= d; i++) { 38615932Smckusick if (el == TR_NIL) { 38715967Smckusick return (i-1); 388758Speter } 389758Speter p = p->chain; 39015967Smckusick if ((p->class != CRANGE) && 39115967Smckusick (constsub = constval(el->list_node.list))) { 3923890Smckusic ap = con.ctype; 3933890Smckusic sub = con.crval; 3943890Smckusic if (sub < p->range[0] || sub > p->range[1]) { 39515932Smckusick error("Subscript value of %D is out of range", (char *) sub); 396758Speter return (0); 3973890Smckusic } 3983890Smckusic sub -= p->range[0]; 3993890Smckusic } else { 4003890Smckusic # ifdef PC 4013890Smckusic precheck( p , "_SUBSC" , "_SUBSCZ" ); 4023890Smckusic # endif PC 40315932Smckusick ap = rvalue(el->list_node.list, NLNIL , RREQ ); 4043890Smckusic if (ap == NIL) { 4053890Smckusic return (0); 4063890Smckusic } 4073890Smckusic # ifdef PC 40810361Smckusick postcheck(p, ap); 40918461Sralph sconv(p2type(ap),PCCT_INT); 4103890Smckusic # endif PC 411758Speter } 41215932Smckusick if (incompat(ap, p->type, el->list_node.list)) { 413758Speter cerror("Array index type incompatible with declared index type"); 414758Speter if (d != 1) { 41515932Smckusick cerror("Error occurred on index number %d", (char *) i); 416758Speter } 417758Speter return (-1); 418758Speter } 41915967Smckusick if (p->class == CRANGE) { 42015986Saoki constsub = FALSE; 42115967Smckusick } else { 42215967Smckusick w = aryconst(np, i); 42315967Smckusick } 424758Speter # ifdef OBJ 4253890Smckusic if (constsub) { 4263890Smckusic sub *= w; 4273890Smckusic if (sub != 0) { 42815933Smckusick w = bytes(sub, sub); 42915932Smckusick (void) put(2, w <= 2 ? O_CON2 : O_CON4, sub); 43015932Smckusick (void) gen(NIL, T_ADD, sizeof(char *), w); 4313890Smckusic } 43215932Smckusick el = el->list_node.next; 4333890Smckusic continue; 4343890Smckusic } 43515967Smckusick if (p->class == CRANGE) { 43615967Smckusick putcbnds(p, 0); 43715967Smckusick putcbnds(p, 1); 43815967Smckusick putcbnds(p, 2); 43915967Smckusick } else if (opt('t') == 0) { 440758Speter switch (w) { 441758Speter case 8: 442758Speter w = 6; 443758Speter case 4: 444758Speter case 2: 445758Speter case 1: 44615932Smckusick (void) put(2, (width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]); 44715932Smckusick el = el->list_node.next; 448758Speter continue; 449758Speter } 450758Speter } 45115967Smckusick if (p->class == CRANGE) { 45215967Smckusick if (width(p) == 4) { 45315967Smckusick put(1, width(ap) != 4 ? O_VINX42 : O_VINX4); 45415967Smckusick } else { 45515967Smckusick put(1, width(ap) != 4 ? O_VINX2 : O_VINX24); 45615967Smckusick } 45715967Smckusick } else { 45815967Smckusick put(4, width(ap) != 4 ? O_INX2 : O_INX4, w, 45915967Smckusick (short)p->range[0], (short)(p->range[1])); 46015967Smckusick } 46115932Smckusick el = el->list_node.next; 4623890Smckusic continue; 463758Speter # endif OBJ 464758Speter # ifdef PC 465758Speter /* 466758Speter * subtract off the lower bound 467758Speter */ 4683890Smckusic if (constsub) { 4693890Smckusic sub *= w; 4703890Smckusic if (sub != 0) { 47118461Sralph putleaf( PCC_ICON , (int) sub , 0 , PCCT_INT , (char *) 0 ); 47218461Sralph putop(PCC_PLUS, PCCM_ADDTYPE(p2type(np->type), PCCTM_PTR)); 4733890Smckusic } 47415932Smckusick el = el->list_node.next; 4753890Smckusic continue; 4763890Smckusic } 47715967Smckusick if (p->class == CRANGE) { 478758Speter /* 47915967Smckusick * if conformant array, subtract off lower bound 480758Speter */ 48115967Smckusick ap = p->nptr[0]; 48215967Smckusick putRV(ap->symbol, (ap->nl_block & 037), ap->value[0], 48315967Smckusick ap->extra_flags, p2type( ap ) ); 48418461Sralph putop( PCC_MINUS, PCCT_INT ); 48515967Smckusick /* 48615967Smckusick * and multiply by the width of the elements 48715967Smckusick */ 48815967Smckusick ap = p->nptr[2]; 48915967Smckusick putRV( 0 , (ap->nl_block & 037), ap->value[0], 49015967Smckusick ap->extra_flags, p2type( ap ) ); 49118461Sralph putop( PCC_MUL , PCCT_INT ); 49215967Smckusick } else { 49315967Smckusick if ( p -> range[ 0 ] != 0 ) { 49418461Sralph putleaf( PCC_ICON , (int) p -> range[0] , 0 , PCCT_INT , (char *) 0 ); 49518461Sralph putop( PCC_MINUS , PCCT_INT ); 49615967Smckusick } 49715967Smckusick /* 49815967Smckusick * multiply by the width of the elements 49915967Smckusick */ 50015967Smckusick if ( w != 1 ) { 50118461Sralph putleaf( PCC_ICON , w , 0 , PCCT_INT , (char *) 0 ); 50218461Sralph putop( PCC_MUL , PCCT_INT ); 50315967Smckusick } 504758Speter } 505758Speter /* 506758Speter * and add it to the base address 507758Speter */ 50818461Sralph putop( PCC_PLUS , PCCM_ADDTYPE( p2type( np -> type ) , PCCTM_PTR ) ); 50915932Smckusick el = el->list_node.next; 510758Speter # endif PC 511758Speter } 51215932Smckusick if (el != TR_NIL) { 51315967Smckusick if (np->type->class != ARRAY) { 514758Speter do { 51515932Smckusick el = el->list_node.next; 516758Speter i++; 51715932Smckusick } while (el != TR_NIL); 51815932Smckusick error("Too many subscripts (%d given, %d required)", (char *) (i-1), (char *) d); 519758Speter return (-1); 52015967Smckusick } else { 52115967Smckusick return(arycod(np->type, el, d)); 52215967Smckusick } 523758Speter } 52415967Smckusick return (d); 525758Speter } 52615967Smckusick 52715967Smckusick #ifdef OBJ 52815967Smckusick /* 52915967Smckusick * Put out the conformant array bounds (lower bound, upper bound or width) 53015967Smckusick * for conformant array type ctype. 53115967Smckusick * The value of i determines which is being put 53215967Smckusick * i = 0: lower bound, i=1: upper bound, i=2: width 53315967Smckusick */ 53415967Smckusick putcbnds(ctype, i) 53515967Smckusick struct nl *ctype; 53615967Smckusick int i; 53715967Smckusick { 53815967Smckusick switch(width(ctype->type)) { 53915967Smckusick case 1: 54015967Smckusick put(2, O_RV1 | (ctype->nl_block & 037) << 8+INDX, 54115967Smckusick (int)ctype->nptr[i]->value[0]); 54215967Smckusick break; 54315967Smckusick case 2: 54415967Smckusick put(2, O_RV2 | (ctype->nl_block & 037) << 8+INDX, 54515967Smckusick (int)ctype->nptr[i]->value[0]); 54615967Smckusick break; 54715967Smckusick case 4: 54815967Smckusick default: 54915967Smckusick put(2, O_RV4 | (ctype->nl_block & 037) << 8+INDX, 55015967Smckusick (int)ctype->nptr[i]->value[0]); 55115967Smckusick } 55215967Smckusick } 55315967Smckusick #endif OBJ 554