xref: /csrg-svn/usr.bin/pascal/src/lval.c (revision 10361)
1758Speter /* Copyright (c) 1979 Regents of the University of California */
2758Speter 
3*10361Smckusick static char sccsid[] = "@(#)lval.c 1.9 01/17/83";
4758Speter 
5758Speter #include "whoami.h"
6758Speter #include "0.h"
7758Speter #include "tree.h"
8758Speter #include "opcode.h"
9758Speter #include "objfmt.h"
10758Speter #ifdef PC
11758Speter #   include	"pc.h"
12758Speter #   include	"pcops.h"
13758Speter #endif PC
14758Speter 
15758Speter extern	int flagwas;
16758Speter /*
17758Speter  * Lvalue computes the address
18758Speter  * of a qualified name and
19758Speter  * leaves it on the stack.
20758Speter  * for pc, it can be asked for either an lvalue or an rvalue.
21758Speter  * the semantics are the same, only the code is different.
22758Speter  */
23758Speter struct nl *
24758Speter lvalue(r, modflag , required )
25758Speter 	int *r, modflag;
26758Speter 	int	required;
27758Speter {
28758Speter 	register struct nl *p;
29758Speter 	struct nl *firstp, *lastp;
30758Speter 	register *c, *co;
31758Speter 	int f, o;
32758Speter 	/*
33758Speter 	 * Note that the local optimizations
34758Speter 	 * done here for offsets would more
35758Speter 	 * appropriately be done in put.
36758Speter 	 */
37758Speter 	int tr[2], trp[3];
38758Speter 
39758Speter 	if (r == NIL) {
40758Speter 		return (NIL);
41758Speter 	}
42758Speter 	if (nowexp(r)) {
43758Speter 		return (NIL);
44758Speter 	}
45758Speter 	if (r[0] != T_VAR) {
46758Speter 		error("Variable required");	/* Pass mesgs down from pt of call ? */
47758Speter 		return (NIL);
48758Speter 	}
49758Speter #	ifdef PC
50758Speter 		/*
51758Speter 		 *	pc requires a whole different control flow
52758Speter 		 */
53758Speter 	    return pclvalue( r , modflag , required );
54758Speter #	endif PC
552122Smckusic #	ifdef OBJ
562122Smckusic 		/*
572122Smckusic 		 *	pi uses the rest of the function
582122Smckusic 		 */
59758Speter 	firstp = p = lookup(r[2]);
60758Speter 	if (p == NIL) {
61758Speter 		return (NIL);
62758Speter 	}
63758Speter 	c = r[3];
64758Speter 	if ((modflag & NOUSE) && !lptr(c)) {
65758Speter 		p->nl_flags = flagwas;
66758Speter 	}
67758Speter 	if (modflag & MOD) {
68758Speter 		p->nl_flags |= NMOD;
69758Speter 	}
70758Speter 	/*
71758Speter 	 * Only possibilities for p->class here
72758Speter 	 * are the named classes, i.e. CONST, TYPE
73758Speter 	 * VAR, PROC, FUNC, REF, or a WITHPTR.
74758Speter 	 */
75758Speter 	switch (p->class) {
76758Speter 		case WITHPTR:
77758Speter 			/*
78758Speter 			 * Construct the tree implied by
79758Speter 			 * the with statement
80758Speter 			 */
81758Speter 			trp[0] = T_LISTPP;
82758Speter 			trp[1] = tr;
83758Speter 			trp[2] = r[3];
84758Speter 			tr[0] = T_FIELD;
85758Speter 			tr[1] = r[2];
86758Speter 			c = trp;
87758Speter #			ifdef PTREE
88758Speter 			    /*
89758Speter 			     * mung r[4] to say which field this T_VAR is
90758Speter 			     * for VarCopy
91758Speter 			     */
92758Speter 			    r[4] = reclook( p -> type , r[2] );
93758Speter #			endif
94758Speter 			/* and fall through */
95758Speter 		case REF:
96758Speter 			/*
97758Speter 			 * Obtain the indirect word
98758Speter 			 * of the WITHPTR or REF
99758Speter 			 * as the base of our lvalue
100758Speter 			 */
1013074Smckusic 			put(2, PTR_RV | bn << 8+INDX , (int)p->value[0] );
102758Speter 			f = 0;		/* have an lv on stack */
103758Speter 			o = 0;
104758Speter 			break;
105758Speter 		case VAR:
106758Speter 			f = 1;		/* no lv on stack yet */
107758Speter 			o = p->value[0];
108758Speter 			break;
109758Speter 		default:
110758Speter 			error("%s %s found where variable required", classes[p->class], p->symbol);
111758Speter 			return (NIL);
112758Speter 	}
113758Speter 	/*
114758Speter 	 * Loop and handle each
115758Speter 	 * qualification on the name
116758Speter 	 */
1173581Speter 	if (c == NIL && (modflag&ASGN) && ( p->value[NL_FORV] & FORVAR ) ) {
118758Speter 		error("Can't modify the for variable %s in the range of the loop", p->symbol);
119758Speter 		return (NIL);
120758Speter 	}
121758Speter 	for (; c != NIL; c = c[2]) {
122758Speter 		co = c[1];
123758Speter 		if (co == NIL) {
124758Speter 			return (NIL);
125758Speter 		}
126758Speter 		lastp = p;
127758Speter 		p = p->type;
128758Speter 		if (p == NIL) {
129758Speter 			return (NIL);
130758Speter 		}
131758Speter 		switch (co[0]) {
132758Speter 			case T_PTR:
133758Speter 				/*
134758Speter 				 * Pointer qualification.
135758Speter 				 */
136758Speter 				lastp->nl_flags |= NUSED;
137758Speter 				if (p->class != PTR && p->class != FILET) {
138758Speter 					error("^ allowed only on files and pointers, not on %ss", nameof(p));
139758Speter 					goto bad;
140758Speter 				}
141758Speter 				if (f) {
1422071Smckusic 				    if (p->class == FILET && bn != 0)
1432071Smckusic 				        put(2, O_LV | bn <<8+INDX , o );
1442071Smckusic 				    else
1452071Smckusic 					/*
1462071Smckusic 					 * this is the indirection from
1472071Smckusic 					 * the address of the pointer
1482071Smckusic 					 * to the pointer itself.
1492071Smckusic 					 * kirk sez:
1502071Smckusic 					 * fnil doesn't want this.
1512071Smckusic 					 * and does it itself for files
1522071Smckusic 					 * since only it knows where the
1532071Smckusic 					 * actual window is.
1542071Smckusic 					 * but i have to do this for
1552071Smckusic 					 * regular pointers.
1562071Smckusic 					 * This is further complicated by
1572071Smckusic 					 * the fact that global variables
1582071Smckusic 					 * are referenced through pointers
1592071Smckusic 					 * on the stack. Thus an RV on a
1602071Smckusic 					 * global variable is the same as
1612071Smckusic 					 * an LV of a non-global one ?!?
1622071Smckusic 					 */
1632071Smckusic 				        put(2, PTR_RV | bn <<8+INDX , o );
164758Speter 				} else {
165758Speter 					if (o) {
1663074Smckusic 					    put(2, O_OFF, o);
167758Speter 					}
1682104Smckusic 				        if (p->class != FILET || bn == 0)
1692104Smckusic 					    put(1, PTR_IND);
170758Speter 				}
171758Speter 				/*
172758Speter 				 * Pointer cannot be
173758Speter 				 * nil and file cannot
174758Speter 				 * be at end-of-file.
175758Speter 				 */
1763074Smckusic 				put(1, p->class == FILET ? O_FNIL : O_NIL);
177758Speter 				f = o = 0;
178758Speter 				continue;
179758Speter 			case T_ARGL:
180758Speter 				if (p->class != ARRAY) {
181758Speter 					if (lastp == firstp) {
182758Speter 						error("%s is a %s, not a function", r[2], classes[firstp->class]);
183758Speter 					} else {
184758Speter 						error("Illegal function qualificiation");
185758Speter 					}
186758Speter 					return (NIL);
187758Speter 				}
188758Speter 				recovered();
189758Speter 				error("Pascal uses [] for subscripting, not ()");
190758Speter 			case T_ARY:
191758Speter 				if (p->class != ARRAY) {
192758Speter 					error("Subscripting allowed only on arrays, not on %ss", nameof(p));
193758Speter 					goto bad;
194758Speter 				}
195758Speter 				if (f) {
1962071Smckusic 					if (bn == 0)
1972071Smckusic 						/*
1982071Smckusic 						 * global variables are
1992071Smckusic 						 * referenced through pointers
2002071Smckusic 						 * on the stack
2012071Smckusic 						 */
2023074Smckusic 						put(2, PTR_RV | bn<<8+INDX, o);
2032071Smckusic 					else
2043074Smckusic 						put(2, O_LV | bn<<8+INDX, o);
205758Speter 				} else {
206758Speter 					if (o) {
2073074Smckusic 					    put(2, O_OFF, o);
208758Speter 					}
209758Speter 				}
210758Speter 				switch (arycod(p, co[1])) {
211758Speter 					case 0:
212758Speter 						return (NIL);
213758Speter 					case -1:
214758Speter 						goto bad;
215758Speter 				}
216758Speter 				f = o = 0;
217758Speter 				continue;
218758Speter 			case T_FIELD:
219758Speter 				/*
220758Speter 				 * Field names are just
221758Speter 				 * an offset with some
222758Speter 				 * semantic checking.
223758Speter 				 */
224758Speter 				if (p->class != RECORD) {
225758Speter 					error(". allowed only on records, not on %ss", nameof(p));
226758Speter 					goto bad;
227758Speter 				}
228758Speter 				if (co[1] == NIL) {
229758Speter 					return (NIL);
230758Speter 				}
231758Speter 				p = reclook(p, co[1]);
232758Speter 				if (p == NIL) {
233758Speter 					error("%s is not a field in this record", co[1]);
234758Speter 					goto bad;
235758Speter 				}
236758Speter #				ifdef PTREE
237758Speter 				    /*
238758Speter 				     * mung co[3] to indicate which field
239758Speter 				     * this is for SelCopy
240758Speter 				     */
241758Speter 				    co[3] = p;
242758Speter #				endif
243758Speter 				if (modflag & MOD) {
244758Speter 					p->nl_flags |= NMOD;
245758Speter 				}
246758Speter 				if ((modflag & NOUSE) == 0 || lptr(c[2])) {
247758Speter 					p->nl_flags |= NUSED;
248758Speter 				}
249758Speter 				o += p->value[0];
250758Speter 				continue;
251758Speter 			default:
252758Speter 				panic("lval2");
253758Speter 		}
254758Speter 	}
255758Speter 	if (f) {
2562071Smckusic 		if (bn == 0)
2572071Smckusic 			/*
2582071Smckusic 			 * global variables are referenced through
2592071Smckusic 			 * pointers on the stack
2602071Smckusic 			 */
2613074Smckusic 			put(2, PTR_RV | bn<<8+INDX, o);
2622071Smckusic 		else
2633074Smckusic 			put(2, O_LV | bn<<8+INDX, o);
264758Speter 	} else {
265758Speter 		if (o) {
2663074Smckusic 		    put(2, O_OFF, o);
267758Speter 		}
268758Speter 	}
269758Speter 	return (p->type);
270758Speter bad:
271758Speter 	cerror("Error occurred on qualification of %s", r[2]);
272758Speter 	return (NIL);
2732122Smckusic #	endif OBJ
274758Speter }
275758Speter 
276758Speter lptr(c)
277758Speter 	register int *c;
278758Speter {
279758Speter 	register int *co;
280758Speter 
281758Speter 	for (; c != NIL; c = c[2]) {
282758Speter 		co = c[1];
283758Speter 		if (co == NIL) {
284758Speter 			return (NIL);
285758Speter 		}
286758Speter 		switch (co[0]) {
287758Speter 
288758Speter 		case T_PTR:
289758Speter 			return (1);
290758Speter 		case T_ARGL:
291758Speter 			return (0);
292758Speter 		case T_ARY:
293758Speter 		case T_FIELD:
294758Speter 			continue;
295758Speter 		default:
296758Speter 			panic("lptr");
297758Speter 		}
298758Speter 	}
299758Speter 	return (0);
300758Speter }
301758Speter 
302758Speter /*
303758Speter  * Arycod does the
304758Speter  * code generation
305758Speter  * for subscripting.
306758Speter  */
307758Speter arycod(np, el)
308758Speter 	struct nl *np;
309758Speter 	int *el;
310758Speter {
311758Speter 	register struct nl *p, *ap;
3123890Smckusic 	long sub;
3133890Smckusic 	bool constsub;
314758Speter 	int i, d, v, v1;
315758Speter 	int w;
316758Speter 
317758Speter 	p = np;
318758Speter 	if (el == NIL) {
319758Speter 		return (0);
320758Speter 	}
321758Speter 	d = p->value[0];
322758Speter 	/*
323758Speter 	 * Check each subscript
324758Speter 	 */
325758Speter 	for (i = 1; i <= d; i++) {
326758Speter 		if (el == NIL) {
327758Speter 			error("Too few subscripts (%d given, %d required)", i-1, d);
328758Speter 			return (-1);
329758Speter 		}
330758Speter 		p = p->chain;
3313890Smckusic 		if (constsub = constval(el[1])) {
3323890Smckusic 		    ap = con.ctype;
3333890Smckusic 		    sub = con.crval;
3343890Smckusic 		    if (sub < p->range[0] || sub > p->range[1]) {
3353890Smckusic 			error("Subscript value of %D is out of range", sub);
336758Speter 			return (0);
3373890Smckusic 		    }
3383890Smckusic 		    sub -= p->range[0];
3393890Smckusic 		} else {
3403890Smckusic #		    ifdef PC
3413890Smckusic 			precheck( p , "_SUBSC" , "_SUBSCZ" );
3423890Smckusic #		    endif PC
3433890Smckusic 		    ap = rvalue(el[1], NLNIL , RREQ );
3443890Smckusic 		    if (ap == NIL) {
3453890Smckusic 			    return (0);
3463890Smckusic 		    }
3473890Smckusic #		    ifdef PC
348*10361Smckusick 			postcheck(p, ap);
349*10361Smckusick 			sconv(p2type(ap),P2INT);
3503890Smckusic #		    endif PC
351758Speter 		}
352758Speter 		if (incompat(ap, p->type, el[1])) {
353758Speter 			cerror("Array index type incompatible with declared index type");
354758Speter 			if (d != 1) {
355758Speter 				cerror("Error occurred on index number %d", i);
356758Speter 			}
357758Speter 			return (-1);
358758Speter 		}
359758Speter 		w = aryconst(np, i);
360758Speter #		ifdef OBJ
3613890Smckusic 		    if (constsub) {
3623890Smckusic 			sub *= w;
3633890Smckusic 			if (sub != 0) {
3643890Smckusic 			    w = width(ap);
3653890Smckusic 			    put(2, w <= 2 ? O_CON2 : O_CON4, sub);
3663890Smckusic 			    gen(NIL, T_ADD, sizeof(char *), w);
3673890Smckusic 			}
3683890Smckusic 			el = el[2];
3693890Smckusic 			continue;
3703890Smckusic 		    }
371758Speter 		    if (opt('t') == 0) {
372758Speter 			    switch (w) {
373758Speter 			    case 8:
374758Speter 				    w = 6;
375758Speter 			    case 4:
376758Speter 			    case 2:
377758Speter 			    case 1:
3783074Smckusic 				    put(2, (width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]);
379758Speter 				    el = el[2];
380758Speter 				    continue;
381758Speter 			    }
382758Speter 		    }
3833074Smckusic 		    put(4, width(ap) != 4 ? O_INX2 : O_INX4, w,
3843074Smckusic 			(short)p->range[0], (short)(p->range[1]));
3853890Smckusic 		    el = el[2];
3863890Smckusic 		    continue;
387758Speter #		endif OBJ
388758Speter #		ifdef PC
389758Speter 			/*
390758Speter 			 *	subtract off the lower bound
391758Speter 			 */
3923890Smckusic 		    if (constsub) {
3933890Smckusic 			sub *= w;
3943890Smckusic 			if (sub != 0) {
3953890Smckusic 			    putleaf( P2ICON , sub , 0 , P2INT , 0 );
3963890Smckusic 			    putop(P2PLUS, ADDTYPE(p2type(np->type), P2PTR));
3973890Smckusic 			}
3983890Smckusic 			el = el[2];
3993890Smckusic 			continue;
4003890Smckusic 		    }
401758Speter 		    if ( p -> range[ 0 ] != 0 ) {
402758Speter 			putleaf( P2ICON , p -> range[0] , 0 , P2INT , 0 );
403758Speter 			putop( P2MINUS , P2INT );
404758Speter 		    }
405758Speter 			/*
406758Speter 			 *	multiply by the width of the elements
407758Speter 			 */
408758Speter 		    if ( w != 1 ) {
409758Speter 			putleaf( P2ICON , w , 0 , P2INT , 0 );
410758Speter 			putop( P2MUL , P2INT );
411758Speter 		    }
412758Speter 			/*
413758Speter 			 *	and add it to the base address
414758Speter 			 */
415758Speter 		    putop( P2PLUS , ADDTYPE( p2type( np -> type ) , P2PTR ) );
416758Speter #		endif PC
417758Speter 		el = el[2];
418758Speter 	}
419758Speter 	if (el != NIL) {
420758Speter 		do {
421758Speter 			el = el[2];
422758Speter 			i++;
423758Speter 		} while (el != NIL);
424758Speter 		error("Too many subscripts (%d given, %d required)", i-1, d);
425758Speter 		return (-1);
426758Speter 	}
427758Speter 	return (1);
428758Speter }
429