xref: /csrg-svn/usr.bin/pascal/src/lval.c (revision 15932)
1758Speter /* Copyright (c) 1979 Regents of the University of California */
2758Speter 
3*15932Smckusick #ifndef lint
4*15932Smckusick static char sccsid[] = "@(#)lval.c 1.9.1.1 02/04/84";
5*15932Smckusick #endif
6758Speter 
7758Speter #include "whoami.h"
8758Speter #include "0.h"
9758Speter #include "tree.h"
10758Speter #include "opcode.h"
11758Speter #include "objfmt.h"
12*15932Smckusick #include "tree_ty.h"
13758Speter #ifdef PC
14758Speter #   include	"pc.h"
15758Speter #   include	"pcops.h"
16758Speter #endif PC
17758Speter 
18758Speter extern	int flagwas;
19758Speter /*
20758Speter  * Lvalue computes the address
21758Speter  * of a qualified name and
22758Speter  * leaves it on the stack.
23758Speter  * for pc, it can be asked for either an lvalue or an rvalue.
24758Speter  * the semantics are the same, only the code is different.
25758Speter  */
26*15932Smckusick /*ARGSUSED*/
27758Speter struct nl *
28*15932Smckusick lvalue(var, modflag , required )
29*15932Smckusick 	struct tnode *var;
30*15932Smckusick 	int	modflag;
31758Speter 	int	required;
32758Speter {
33*15932Smckusick #ifdef OBJ
34758Speter 	register struct nl *p;
35758Speter 	struct nl *firstp, *lastp;
36*15932Smckusick 	register struct tnode *c, *co;
37758Speter 	int f, o;
38758Speter 	/*
39758Speter 	 * Note that the local optimizations
40758Speter 	 * done here for offsets would more
41758Speter 	 * appropriately be done in put.
42758Speter 	 */
43*15932Smckusick 	struct tnode	tr;	/* T_FIELD */
44*15932Smckusick 	struct tnode	*tr_ptr;
45*15932Smckusick 	struct tnode	l_node;
46*15932Smckusick #endif
47758Speter 
48*15932Smckusick 	if (var == TR_NIL) {
49*15932Smckusick 		return (NLNIL);
50758Speter 	}
51*15932Smckusick 	if (nowexp(var)) {
52*15932Smckusick 		return (NLNIL);
53758Speter 	}
54*15932Smckusick 	if (var->tag != T_VAR) {
55758Speter 		error("Variable required");	/* Pass mesgs down from pt of call ? */
56*15932Smckusick 		return (NLNIL);
57758Speter 	}
58758Speter #	ifdef PC
59758Speter 		/*
60758Speter 		 *	pc requires a whole different control flow
61758Speter 		 */
62*15932Smckusick 	    return pclvalue( var , modflag , required );
63758Speter #	endif PC
642122Smckusic #	ifdef OBJ
652122Smckusic 		/*
662122Smckusic 		 *	pi uses the rest of the function
672122Smckusic 		 */
68*15932Smckusick 	firstp = p = lookup(var->var_node.cptr);
69*15932Smckusick 	if (p == NLNIL) {
70*15932Smckusick 		return (NLNIL);
71758Speter 	}
72*15932Smckusick 	c = var->var_node.qual;
73758Speter 	if ((modflag & NOUSE) && !lptr(c)) {
74758Speter 		p->nl_flags = flagwas;
75758Speter 	}
76758Speter 	if (modflag & MOD) {
77758Speter 		p->nl_flags |= NMOD;
78758Speter 	}
79758Speter 	/*
80758Speter 	 * Only possibilities for p->class here
81758Speter 	 * are the named classes, i.e. CONST, TYPE
82758Speter 	 * VAR, PROC, FUNC, REF, or a WITHPTR.
83758Speter 	 */
84*15932Smckusick 	tr_ptr = &l_node;
85758Speter 	switch (p->class) {
86758Speter 		case WITHPTR:
87758Speter 			/*
88758Speter 			 * Construct the tree implied by
89758Speter 			 * the with statement
90758Speter 			 */
91*15932Smckusick 			l_node.tag = T_LISTPP;
92*15932Smckusick 
93*15932Smckusick 			/* the cast has got to go but until the node is figured
94*15932Smckusick 			   out it stays */
95*15932Smckusick 
96*15932Smckusick 			tr_ptr->list_node.list = (&tr);
97*15932Smckusick 			tr_ptr->list_node.next = var->var_node.qual;
98*15932Smckusick 			tr.tag = T_FIELD;
99*15932Smckusick 			tr.field_node.id_ptr = var->var_node.cptr;
100*15932Smckusick 			c = tr_ptr; /* c is a ptr to a tnode */
101758Speter #			ifdef PTREE
102758Speter 			    /*
103*15932Smckusick 			     * mung var->fields to say which field this T_VAR is
104758Speter 			     * for VarCopy
105758Speter 			     */
106*15932Smckusick 
107*15932Smckusick 			    /* problem! reclook returns struct nl* */
108*15932Smckusick 
109*15932Smckusick 			    var->var_node.fields = reclook( p -> type ,
110*15932Smckusick 					    var->var_node.line_no );
111758Speter #			endif
112758Speter 			/* and fall through */
113758Speter 		case REF:
114758Speter 			/*
115758Speter 			 * Obtain the indirect word
116758Speter 			 * of the WITHPTR or REF
117758Speter 			 * as the base of our lvalue
118758Speter 			 */
119*15932Smckusick 			(void) put(2, PTR_RV | bn << 8+INDX , (int)p->value[0] );
120758Speter 			f = 0;		/* have an lv on stack */
121758Speter 			o = 0;
122758Speter 			break;
123758Speter 		case VAR:
124758Speter 			f = 1;		/* no lv on stack yet */
125758Speter 			o = p->value[0];
126758Speter 			break;
127758Speter 		default:
128758Speter 			error("%s %s found where variable required", classes[p->class], p->symbol);
129*15932Smckusick 			return (NLNIL);
130758Speter 	}
131758Speter 	/*
132758Speter 	 * Loop and handle each
133758Speter 	 * qualification on the name
134758Speter 	 */
135*15932Smckusick 	if (c == TR_NIL && (modflag&ASGN) && ( p->value[NL_FORV] & FORVAR ) ) {
136758Speter 		error("Can't modify the for variable %s in the range of the loop", p->symbol);
137*15932Smckusick 		return (NLNIL);
138758Speter 	}
139*15932Smckusick 	for (; c != TR_NIL; c = c->list_node.next) {
140*15932Smckusick 		co = c->list_node.list; /* co is a ptr to a tnode */
141*15932Smckusick 		if (co == TR_NIL) {
142*15932Smckusick 			return (NLNIL);
143758Speter 		}
144758Speter 		lastp = p;
145758Speter 		p = p->type;
146*15932Smckusick 		if (p == NLNIL) {
147*15932Smckusick 			return (NLNIL);
148758Speter 		}
149*15932Smckusick 		switch (co->tag) {
150758Speter 			case T_PTR:
151758Speter 				/*
152758Speter 				 * Pointer qualification.
153758Speter 				 */
154758Speter 				lastp->nl_flags |= NUSED;
155758Speter 				if (p->class != PTR && p->class != FILET) {
156758Speter 					error("^ allowed only on files and pointers, not on %ss", nameof(p));
157758Speter 					goto bad;
158758Speter 				}
159758Speter 				if (f) {
1602071Smckusic 				    if (p->class == FILET && bn != 0)
161*15932Smckusick 				        (void) put(2, O_LV | bn <<8+INDX , o );
1622071Smckusic 				    else
1632071Smckusic 					/*
1642071Smckusic 					 * this is the indirection from
1652071Smckusic 					 * the address of the pointer
1662071Smckusic 					 * to the pointer itself.
1672071Smckusic 					 * kirk sez:
1682071Smckusic 					 * fnil doesn't want this.
1692071Smckusic 					 * and does it itself for files
1702071Smckusic 					 * since only it knows where the
1712071Smckusic 					 * actual window is.
1722071Smckusic 					 * but i have to do this for
1732071Smckusic 					 * regular pointers.
1742071Smckusic 					 * This is further complicated by
1752071Smckusic 					 * the fact that global variables
1762071Smckusic 					 * are referenced through pointers
1772071Smckusic 					 * on the stack. Thus an RV on a
1782071Smckusic 					 * global variable is the same as
1792071Smckusic 					 * an LV of a non-global one ?!?
1802071Smckusic 					 */
181*15932Smckusick 				        (void) put(2, PTR_RV | bn <<8+INDX , o );
182758Speter 				} else {
183758Speter 					if (o) {
184*15932Smckusick 					    (void) put(2, O_OFF, o);
185758Speter 					}
1862104Smckusic 				        if (p->class != FILET || bn == 0)
187*15932Smckusick 					    (void) put(1, PTR_IND);
188758Speter 				}
189758Speter 				/*
190758Speter 				 * Pointer cannot be
191758Speter 				 * nil and file cannot
192758Speter 				 * be at end-of-file.
193758Speter 				 */
194*15932Smckusick 				(void) put(1, p->class == FILET ? O_FNIL : O_NIL);
195758Speter 				f = o = 0;
196758Speter 				continue;
197758Speter 			case T_ARGL:
198758Speter 				if (p->class != ARRAY) {
199758Speter 					if (lastp == firstp) {
200*15932Smckusick 						error("%s is a %s, not a function", var->var_node.cptr, classes[firstp->class]);
201758Speter 					} else {
202758Speter 						error("Illegal function qualificiation");
203758Speter 					}
204*15932Smckusick 					return (NLNIL);
205758Speter 				}
206758Speter 				recovered();
207758Speter 				error("Pascal uses [] for subscripting, not ()");
208758Speter 			case T_ARY:
209758Speter 				if (p->class != ARRAY) {
210758Speter 					error("Subscripting allowed only on arrays, not on %ss", nameof(p));
211758Speter 					goto bad;
212758Speter 				}
213758Speter 				if (f) {
2142071Smckusic 					if (bn == 0)
2152071Smckusic 						/*
2162071Smckusic 						 * global variables are
2172071Smckusic 						 * referenced through pointers
2182071Smckusic 						 * on the stack
2192071Smckusic 						 */
220*15932Smckusick 						(void) put(2, PTR_RV | bn<<8+INDX, o);
2212071Smckusic 					else
222*15932Smckusick 						(void) put(2, O_LV | bn<<8+INDX, o);
223758Speter 				} else {
224758Speter 					if (o) {
225*15932Smckusick 					    (void) put(2, O_OFF, o);
226758Speter 					}
227758Speter 				}
228*15932Smckusick 				switch (arycod(p, co->ary_node.expr_list)) {
229758Speter 					case 0:
230*15932Smckusick 						return (NLNIL);
231758Speter 					case -1:
232758Speter 						goto bad;
233758Speter 				}
234758Speter 				f = o = 0;
235758Speter 				continue;
236758Speter 			case T_FIELD:
237758Speter 				/*
238758Speter 				 * Field names are just
239758Speter 				 * an offset with some
240758Speter 				 * semantic checking.
241758Speter 				 */
242758Speter 				if (p->class != RECORD) {
243758Speter 					error(". allowed only on records, not on %ss", nameof(p));
244758Speter 					goto bad;
245758Speter 				}
246*15932Smckusick 				/* must define the field node!! */
247*15932Smckusick 				if (co->field_node.id_ptr == NIL) {
248*15932Smckusick 					return (NLNIL);
249758Speter 				}
250*15932Smckusick 				p = reclook(p, co->field_node.id_ptr);
251*15932Smckusick 				if (p == NLNIL) {
252*15932Smckusick 					error("%s is not a field in this record", co->field_node.id_ptr);
253758Speter 					goto bad;
254758Speter 				}
255758Speter #				ifdef PTREE
256758Speter 				    /*
257758Speter 				     * mung co[3] to indicate which field
258758Speter 				     * this is for SelCopy
259758Speter 				     */
260*15932Smckusick 				    co->field_node.nl_entry = p;
261758Speter #				endif
262758Speter 				if (modflag & MOD) {
263758Speter 					p->nl_flags |= NMOD;
264758Speter 				}
265*15932Smckusick 				if ((modflag & NOUSE) == 0 ||
266*15932Smckusick 				    lptr(c->list_node.next)) {
267*15932Smckusick 				/* figure out what kind of node c is !! */
268758Speter 					p->nl_flags |= NUSED;
269758Speter 				}
270758Speter 				o += p->value[0];
271758Speter 				continue;
272758Speter 			default:
273758Speter 				panic("lval2");
274758Speter 		}
275758Speter 	}
276758Speter 	if (f) {
2772071Smckusic 		if (bn == 0)
2782071Smckusic 			/*
2792071Smckusic 			 * global variables are referenced through
2802071Smckusic 			 * pointers on the stack
2812071Smckusic 			 */
282*15932Smckusick 			(void) put(2, PTR_RV | bn<<8+INDX, o);
2832071Smckusic 		else
284*15932Smckusick 			(void) put(2, O_LV | bn<<8+INDX, o);
285758Speter 	} else {
286758Speter 		if (o) {
287*15932Smckusick 		    (void) put(2, O_OFF, o);
288758Speter 		}
289758Speter 	}
290758Speter 	return (p->type);
291758Speter bad:
292*15932Smckusick 	cerror("Error occurred on qualification of %s", var->var_node.cptr);
293*15932Smckusick 	return (NLNIL);
2942122Smckusic #	endif OBJ
295758Speter }
296758Speter 
297*15932Smckusick int lptr(c)
298*15932Smckusick 	register struct tnode *c;
299758Speter {
300*15932Smckusick 	register struct tnode *co;
301758Speter 
302*15932Smckusick 	for (; c != TR_NIL; c = c->list_node.next) {
303*15932Smckusick 		co = c->list_node.list;
304*15932Smckusick 		if (co == TR_NIL) {
305758Speter 			return (NIL);
306758Speter 		}
307*15932Smckusick 		switch (co->tag) {
308758Speter 
309758Speter 		case T_PTR:
310758Speter 			return (1);
311758Speter 		case T_ARGL:
312758Speter 			return (0);
313758Speter 		case T_ARY:
314758Speter 		case T_FIELD:
315758Speter 			continue;
316758Speter 		default:
317758Speter 			panic("lptr");
318758Speter 		}
319758Speter 	}
320758Speter 	return (0);
321758Speter }
322758Speter 
323758Speter /*
324758Speter  * Arycod does the
325758Speter  * code generation
326758Speter  * for subscripting.
327758Speter  */
328*15932Smckusick int arycod(np, el)
329758Speter 	struct nl *np;
330*15932Smckusick 	struct tnode *el;
331758Speter {
332758Speter 	register struct nl *p, *ap;
3333890Smckusic 	long sub;
3343890Smckusic 	bool constsub;
335*15932Smckusick 	extern bool constval();
336*15932Smckusick 	int i, d;  /* v, v1;  these aren't used */
337758Speter 	int w;
338758Speter 
339758Speter 	p = np;
340*15932Smckusick 	if (el == TR_NIL) {
341758Speter 		return (0);
342758Speter 	}
343758Speter 	d = p->value[0];
344758Speter 	/*
345758Speter 	 * Check each subscript
346758Speter 	 */
347758Speter 	for (i = 1; i <= d; i++) {
348*15932Smckusick 		if (el == TR_NIL) {
349*15932Smckusick 			error("Too few subscripts (%d given, %d required)", (char *) i-1, (char *) d);
350758Speter 			return (-1);
351758Speter 		}
352758Speter 		p = p->chain;
353*15932Smckusick 		if (constsub = constval(el->list_node.list)) {
3543890Smckusic 		    ap = con.ctype;
3553890Smckusic 		    sub = con.crval;
3563890Smckusic 		    if (sub < p->range[0] || sub > p->range[1]) {
357*15932Smckusick 			error("Subscript value of %D is out of range", (char *) sub);
358758Speter 			return (0);
3593890Smckusic 		    }
3603890Smckusic 		    sub -= p->range[0];
3613890Smckusic 		} else {
3623890Smckusic #		    ifdef PC
3633890Smckusic 			precheck( p , "_SUBSC" , "_SUBSCZ" );
3643890Smckusic #		    endif PC
365*15932Smckusick 		    ap = rvalue(el->list_node.list, NLNIL , RREQ );
3663890Smckusic 		    if (ap == NIL) {
3673890Smckusic 			    return (0);
3683890Smckusic 		    }
3693890Smckusic #		    ifdef PC
37010361Smckusick 			postcheck(p, ap);
37110361Smckusick 			sconv(p2type(ap),P2INT);
3723890Smckusic #		    endif PC
373758Speter 		}
374*15932Smckusick 		if (incompat(ap, p->type, el->list_node.list)) {
375758Speter 			cerror("Array index type incompatible with declared index type");
376758Speter 			if (d != 1) {
377*15932Smckusick 				cerror("Error occurred on index number %d", (char *) i);
378758Speter 			}
379758Speter 			return (-1);
380758Speter 		}
381758Speter 		w = aryconst(np, i);
382758Speter #		ifdef OBJ
3833890Smckusic 		    if (constsub) {
3843890Smckusic 			sub *= w;
3853890Smckusic 			if (sub != 0) {
386*15932Smckusick 			    w = width(ap);
387*15932Smckusick 			    (void) put(2, w <= 2 ? O_CON2 : O_CON4, sub);
388*15932Smckusick 			    (void) gen(NIL, T_ADD, sizeof(char *), w);
3893890Smckusic 			}
390*15932Smckusick 			el = el->list_node.next;
3913890Smckusic 			continue;
3923890Smckusic 		    }
393758Speter 		    if (opt('t') == 0) {
394758Speter 			    switch (w) {
395758Speter 			    case 8:
396758Speter 				    w = 6;
397758Speter 			    case 4:
398758Speter 			    case 2:
399758Speter 			    case 1:
400*15932Smckusick 				    (void) put(2, (width(ap) != 4 ? O_INX2P2 : O_INX4P2) | (w & ~1) << 7, ( short ) p->range[0]);
401*15932Smckusick 				    el = el->list_node.next;
402758Speter 				    continue;
403758Speter 			    }
404758Speter 		    }
405*15932Smckusick 		    (void) put(4, width(ap) != 4 ? O_INX2 : O_INX4, w,
4063074Smckusic 			(short)p->range[0], (short)(p->range[1]));
407*15932Smckusick 		    el = el->list_node.next;
4083890Smckusic 		    continue;
409758Speter #		endif OBJ
410758Speter #		ifdef PC
411758Speter 			/*
412758Speter 			 *	subtract off the lower bound
413758Speter 			 */
4143890Smckusic 		    if (constsub) {
4153890Smckusic 			sub *= w;
4163890Smckusic 			if (sub != 0) {
417*15932Smckusick 			    putleaf( P2ICON , (int) sub , 0 , P2INT , (char *) 0 );
4183890Smckusic 			    putop(P2PLUS, ADDTYPE(p2type(np->type), P2PTR));
4193890Smckusic 			}
420*15932Smckusick 			el = el->list_node.next;
4213890Smckusic 			continue;
4223890Smckusic 		    }
423758Speter 		    if ( p -> range[ 0 ] != 0 ) {
424*15932Smckusick 			putleaf( P2ICON , (int) p -> range[0] , 0 , P2INT , (char *) 0 );
425758Speter 			putop( P2MINUS , P2INT );
426758Speter 		    }
427758Speter 			/*
428758Speter 			 *	multiply by the width of the elements
429758Speter 			 */
430758Speter 		    if ( w != 1 ) {
431*15932Smckusick 			putleaf( P2ICON , w , 0 , P2INT , (char *) 0 );
432758Speter 			putop( P2MUL , P2INT );
433758Speter 		    }
434758Speter 			/*
435758Speter 			 *	and add it to the base address
436758Speter 			 */
437758Speter 		    putop( P2PLUS , ADDTYPE( p2type( np -> type ) , P2PTR ) );
438*15932Smckusick 		el = el->list_node.next;
439758Speter #		endif PC
440758Speter 	}
441*15932Smckusick 	if (el != TR_NIL) {
442758Speter 		do {
443*15932Smckusick 			el = el->list_node.next;
444758Speter 			i++;
445*15932Smckusick 		} while (el != TR_NIL);
446*15932Smckusick 		error("Too many subscripts (%d given, %d required)", (char *) (i-1), (char *) d);
447758Speter 		return (-1);
448758Speter 	}
449758Speter 	return (1);
450758Speter }
451