148116Sbostic /*-
2*62213Sbostic * Copyright (c) 1980, 1993
3*62213Sbostic * The Regents of the University of California. All rights reserved.
448116Sbostic *
548116Sbostic * %sccs.include.redist.c%
622175Sdist */
7758Speter
815932Smckusick #ifndef lint
9*62213Sbostic static char sccsid[] = "@(#)lval.c 8.1 (Berkeley) 06/06/93";
1048116Sbostic #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 *
lvalue(var,modflag,required)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
lptr(c)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 */
arycod(np,el,n)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