xref: /csrg-svn/usr.bin/pascal/src/lval.c (revision 758)
1*758Speter /* Copyright (c) 1979 Regents of the University of California */
2*758Speter 
3*758Speter static	char sccsid[] = "@(#)lval.c 1.1 08/27/80";
4*758Speter 
5*758Speter #include "whoami.h"
6*758Speter #include "0.h"
7*758Speter #include "tree.h"
8*758Speter #include "opcode.h"
9*758Speter #include "objfmt.h"
10*758Speter #ifdef PC
11*758Speter #   include	"pc.h"
12*758Speter #   include	"pcops.h"
13*758Speter #endif PC
14*758Speter 
15*758Speter extern	int flagwas;
16*758Speter /*
17*758Speter  * Lvalue computes the address
18*758Speter  * of a qualified name and
19*758Speter  * leaves it on the stack.
20*758Speter  * for pc, it can be asked for either an lvalue or an rvalue.
21*758Speter  * the semantics are the same, only the code is different.
22*758Speter  */
23*758Speter struct nl *
24*758Speter lvalue(r, modflag , required )
25*758Speter 	int *r, modflag;
26*758Speter 	int	required;
27*758Speter {
28*758Speter 	register struct nl *p;
29*758Speter 	struct nl *firstp, *lastp;
30*758Speter 	register *c, *co;
31*758Speter 	int f, o;
32*758Speter 	/*
33*758Speter 	 * Note that the local optimizations
34*758Speter 	 * done here for offsets would more
35*758Speter 	 * appropriately be done in put.
36*758Speter 	 */
37*758Speter 	int tr[2], trp[3];
38*758Speter 
39*758Speter 	if (r == NIL) {
40*758Speter 		return (NIL);
41*758Speter 	}
42*758Speter 	if (nowexp(r)) {
43*758Speter 		return (NIL);
44*758Speter 	}
45*758Speter 	if (r[0] != T_VAR) {
46*758Speter 		error("Variable required");	/* Pass mesgs down from pt of call ? */
47*758Speter 		return (NIL);
48*758Speter 	}
49*758Speter #	ifdef PC
50*758Speter 		/*
51*758Speter 		 *	pc requires a whole different control flow
52*758Speter 		 */
53*758Speter 	    return pclvalue( r , modflag , required );
54*758Speter #	endif PC
55*758Speter 	firstp = p = lookup(r[2]);
56*758Speter 	if (p == NIL) {
57*758Speter 		return (NIL);
58*758Speter 	}
59*758Speter 	c = r[3];
60*758Speter 	if ((modflag & NOUSE) && !lptr(c)) {
61*758Speter 		p->nl_flags = flagwas;
62*758Speter 	}
63*758Speter 	if (modflag & MOD) {
64*758Speter 		p->nl_flags |= NMOD;
65*758Speter 	}
66*758Speter 	/*
67*758Speter 	 * Only possibilities for p->class here
68*758Speter 	 * are the named classes, i.e. CONST, TYPE
69*758Speter 	 * VAR, PROC, FUNC, REF, or a WITHPTR.
70*758Speter 	 */
71*758Speter 	switch (p->class) {
72*758Speter 		case WITHPTR:
73*758Speter 			/*
74*758Speter 			 * Construct the tree implied by
75*758Speter 			 * the with statement
76*758Speter 			 */
77*758Speter 			trp[0] = T_LISTPP;
78*758Speter 			trp[1] = tr;
79*758Speter 			trp[2] = r[3];
80*758Speter 			tr[0] = T_FIELD;
81*758Speter 			tr[1] = r[2];
82*758Speter 			c = trp;
83*758Speter #			ifdef PTREE
84*758Speter 			    /*
85*758Speter 			     * mung r[4] to say which field this T_VAR is
86*758Speter 			     * for VarCopy
87*758Speter 			     */
88*758Speter 			    r[4] = reclook( p -> type , r[2] );
89*758Speter #			endif
90*758Speter 			/* and fall through */
91*758Speter 		case REF:
92*758Speter 			/*
93*758Speter 			 * Obtain the indirect word
94*758Speter 			 * of the WITHPTR or REF
95*758Speter 			 * as the base of our lvalue
96*758Speter 			 */
97*758Speter 			put(2, PTR_RV | bn << 8+INDX , p->value[0] );
98*758Speter 			f = 0;		/* have an lv on stack */
99*758Speter 			o = 0;
100*758Speter 			break;
101*758Speter 		case VAR:
102*758Speter 			f = 1;		/* no lv on stack yet */
103*758Speter 			o = p->value[0];
104*758Speter 			break;
105*758Speter 		default:
106*758Speter 			error("%s %s found where variable required", classes[p->class], p->symbol);
107*758Speter 			return (NIL);
108*758Speter 	}
109*758Speter 	/*
110*758Speter 	 * Loop and handle each
111*758Speter 	 * qualification on the name
112*758Speter 	 */
113*758Speter 	if (c == NIL && (modflag&ASGN) && p->value[NL_FORV]) {
114*758Speter 		error("Can't modify the for variable %s in the range of the loop", p->symbol);
115*758Speter 		return (NIL);
116*758Speter 	}
117*758Speter 	for (; c != NIL; c = c[2]) {
118*758Speter 		co = c[1];
119*758Speter 		if (co == NIL) {
120*758Speter 			return (NIL);
121*758Speter 		}
122*758Speter 		lastp = p;
123*758Speter 		p = p->type;
124*758Speter 		if (p == NIL) {
125*758Speter 			return (NIL);
126*758Speter 		}
127*758Speter 		switch (co[0]) {
128*758Speter 			case T_PTR:
129*758Speter 				/*
130*758Speter 				 * Pointer qualification.
131*758Speter 				 */
132*758Speter 				lastp->nl_flags |= NUSED;
133*758Speter 				if (p->class != PTR && p->class != FILET) {
134*758Speter 					error("^ allowed only on files and pointers, not on %ss", nameof(p));
135*758Speter 					goto bad;
136*758Speter 				}
137*758Speter 				if (f) {
138*758Speter 				    put(2, PTR_RV | bn <<8+INDX , o );
139*758Speter 				} else {
140*758Speter 					if (o) {
141*758Speter 					    put2(O_OFF, o);
142*758Speter 					}
143*758Speter 					put(1, PTR_IND);
144*758Speter 				}
145*758Speter 				/*
146*758Speter 				 * Pointer cannot be
147*758Speter 				 * nil and file cannot
148*758Speter 				 * be at end-of-file.
149*758Speter 				 */
150*758Speter 				put1(p->class == FILET ? O_FNIL : O_NIL);
151*758Speter 				f = o = 0;
152*758Speter 				continue;
153*758Speter 			case T_ARGL:
154*758Speter 				if (p->class != ARRAY) {
155*758Speter 					if (lastp == firstp) {
156*758Speter 						error("%s is a %s, not a function", r[2], classes[firstp->class]);
157*758Speter 					} else {
158*758Speter 						error("Illegal function qualificiation");
159*758Speter 					}
160*758Speter 					return (NIL);
161*758Speter 				}
162*758Speter 				recovered();
163*758Speter 				error("Pascal uses [] for subscripting, not ()");
164*758Speter 			case T_ARY:
165*758Speter 				if (p->class != ARRAY) {
166*758Speter 					error("Subscripting allowed only on arrays, not on %ss", nameof(p));
167*758Speter 					goto bad;
168*758Speter 				}
169*758Speter 				if (f) {
170*758Speter 					put2(O_LV | bn<<8+INDX, o);
171*758Speter 				} else {
172*758Speter 					if (o) {
173*758Speter 					    put2(O_OFF, o);
174*758Speter 					}
175*758Speter 				}
176*758Speter 				switch (arycod(p, co[1])) {
177*758Speter 					case 0:
178*758Speter 						return (NIL);
179*758Speter 					case -1:
180*758Speter 						goto bad;
181*758Speter 				}
182*758Speter 				f = o = 0;
183*758Speter 				continue;
184*758Speter 			case T_FIELD:
185*758Speter 				/*
186*758Speter 				 * Field names are just
187*758Speter 				 * an offset with some
188*758Speter 				 * semantic checking.
189*758Speter 				 */
190*758Speter 				if (p->class != RECORD) {
191*758Speter 					error(". allowed only on records, not on %ss", nameof(p));
192*758Speter 					goto bad;
193*758Speter 				}
194*758Speter 				if (co[1] == NIL) {
195*758Speter 					return (NIL);
196*758Speter 				}
197*758Speter 				p = reclook(p, co[1]);
198*758Speter 				if (p == NIL) {
199*758Speter 					error("%s is not a field in this record", co[1]);
200*758Speter 					goto bad;
201*758Speter 				}
202*758Speter #				ifdef PTREE
203*758Speter 				    /*
204*758Speter 				     * mung co[3] to indicate which field
205*758Speter 				     * this is for SelCopy
206*758Speter 				     */
207*758Speter 				    co[3] = p;
208*758Speter #				endif
209*758Speter 				if (modflag & MOD) {
210*758Speter 					p->nl_flags |= NMOD;
211*758Speter 				}
212*758Speter 				if ((modflag & NOUSE) == 0 || lptr(c[2])) {
213*758Speter 					p->nl_flags |= NUSED;
214*758Speter 				}
215*758Speter 				o += p->value[0];
216*758Speter 				continue;
217*758Speter 			default:
218*758Speter 				panic("lval2");
219*758Speter 		}
220*758Speter 	}
221*758Speter 	if (f) {
222*758Speter 		put2(O_LV | bn<<8+INDX, o);
223*758Speter 	} else {
224*758Speter 		if (o) {
225*758Speter 		    put2(O_OFF, o);
226*758Speter 		}
227*758Speter 	}
228*758Speter 	return (p->type);
229*758Speter bad:
230*758Speter 	cerror("Error occurred on qualification of %s", r[2]);
231*758Speter 	return (NIL);
232*758Speter }
233*758Speter 
234*758Speter lptr(c)
235*758Speter 	register int *c;
236*758Speter {
237*758Speter 	register int *co;
238*758Speter 
239*758Speter 	for (; c != NIL; c = c[2]) {
240*758Speter 		co = c[1];
241*758Speter 		if (co == NIL) {
242*758Speter 			return (NIL);
243*758Speter 		}
244*758Speter 		switch (co[0]) {
245*758Speter 
246*758Speter 		case T_PTR:
247*758Speter 			return (1);
248*758Speter 		case T_ARGL:
249*758Speter 			return (0);
250*758Speter 		case T_ARY:
251*758Speter 		case T_FIELD:
252*758Speter 			continue;
253*758Speter 		default:
254*758Speter 			panic("lptr");
255*758Speter 		}
256*758Speter 	}
257*758Speter 	return (0);
258*758Speter }
259*758Speter 
260*758Speter /*
261*758Speter  * Arycod does the
262*758Speter  * code generation
263*758Speter  * for subscripting.
264*758Speter  */
265*758Speter arycod(np, el)
266*758Speter 	struct nl *np;
267*758Speter 	int *el;
268*758Speter {
269*758Speter 	register struct nl *p, *ap;
270*758Speter 	int i, d, v, v1;
271*758Speter 	int w;
272*758Speter 
273*758Speter 	p = np;
274*758Speter 	if (el == NIL) {
275*758Speter 		return (0);
276*758Speter 	}
277*758Speter 	d = p->value[0];
278*758Speter 	/*
279*758Speter 	 * Check each subscript
280*758Speter 	 */
281*758Speter 	for (i = 1; i <= d; i++) {
282*758Speter 		if (el == NIL) {
283*758Speter 			error("Too few subscripts (%d given, %d required)", i-1, d);
284*758Speter 			return (-1);
285*758Speter 		}
286*758Speter 		p = p->chain;
287*758Speter #		ifdef PC
288*758Speter 		    precheck( p , "_SUBSC" , "_SUBSCZ" );
289*758Speter #		endif PC
290*758Speter 		ap = rvalue(el[1], NLNIL , RREQ );
291*758Speter 		if (ap == NIL) {
292*758Speter 			return (0);
293*758Speter 		}
294*758Speter #		ifdef PC
295*758Speter 		    postcheck( p );
296*758Speter #		endif PC
297*758Speter 		if (incompat(ap, p->type, el[1])) {
298*758Speter 			cerror("Array index type incompatible with declared index type");
299*758Speter 			if (d != 1) {
300*758Speter 				cerror("Error occurred on index number %d", i);
301*758Speter 			}
302*758Speter 			return (-1);
303*758Speter 		}
304*758Speter 		w = aryconst(np, i);
305*758Speter #		ifdef OBJ
306*758Speter 		    if (opt('t') == 0) {
307*758Speter 			    switch (w) {
308*758Speter 			    case 8:
309*758Speter 				    w = 6;
310*758Speter 			    case 4:
311*758Speter 			    case 2:
312*758Speter 			    case 1:
313*758Speter 				    put2((width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]);
314*758Speter 				    el = el[2];
315*758Speter 				    continue;
316*758Speter 			    }
317*758Speter 		    }
318*758Speter 		    put(4, width(ap) != 4 ? O_INX2 : O_INX4,w,( short ) p->range[0],
319*758Speter 			   ( short ) ( p->range[1] - p->range[0] ) );
320*758Speter #		endif OBJ
321*758Speter #		ifdef PC
322*758Speter 			/*
323*758Speter 			 *	subtract off the lower bound
324*758Speter 			 */
325*758Speter 		    if ( p -> range[ 0 ] != 0 ) {
326*758Speter 			putleaf( P2ICON , p -> range[0] , 0 , P2INT , 0 );
327*758Speter 			putop( P2MINUS , P2INT );
328*758Speter 		    }
329*758Speter 			/*
330*758Speter 			 *	multiply by the width of the elements
331*758Speter 			 */
332*758Speter 		    if ( w != 1 ) {
333*758Speter 			putleaf( P2ICON , w , 0 , P2INT , 0 );
334*758Speter 			putop( P2MUL , P2INT );
335*758Speter 		    }
336*758Speter 			/*
337*758Speter 			 *	and add it to the base address
338*758Speter 			 */
339*758Speter 		    putop( P2PLUS , ADDTYPE( p2type( np -> type ) , P2PTR ) );
340*758Speter #		endif PC
341*758Speter 		el = el[2];
342*758Speter 	}
343*758Speter 	if (el != NIL) {
344*758Speter 		do {
345*758Speter 			el = el[2];
346*758Speter 			i++;
347*758Speter 		} while (el != NIL);
348*758Speter 		error("Too many subscripts (%d given, %d required)", i-1, d);
349*758Speter 		return (-1);
350*758Speter 	}
351*758Speter 	return (1);
352*758Speter }
353