xref: /csrg-svn/usr.bin/pascal/src/pclval.c (revision 3583)
1765Speter /* Copyright (c) 1979 Regents of the University of California */
2765Speter 
3*3583Speter static	char sccsid[] = "@(#)pclval.c 1.3 04/21/81";
4765Speter 
5765Speter #include "whoami.h"
6765Speter #include "0.h"
7765Speter #include "tree.h"
8765Speter #include "opcode.h"
9765Speter #include "objfmt.h"
10765Speter #ifdef PC
11765Speter 	/*
12765Speter 	 *	and the rest of the file
13765Speter 	 */
14765Speter #   include	"pc.h"
15765Speter #   include	"pcops.h"
16765Speter 
17765Speter extern	int flagwas;
18765Speter /*
19765Speter  * pclvalue computes the address
20765Speter  * of a qualified name and
21765Speter  * leaves it on the stack.
22765Speter  * for pc, it can be asked for either an lvalue or an rvalue.
23765Speter  * the semantics are the same, only the code is different.
24765Speter  * for putting out calls to check for nil and fnil,
25765Speter  * we have to traverse the list of qualifications twice:
26765Speter  * once to put out the calls and once to put out the address to be checked.
27765Speter  */
28765Speter struct nl *
29765Speter pclvalue( r , modflag , required )
30765Speter 	int	*r;
31765Speter 	int	modflag;
32765Speter 	int	required;
33765Speter {
34765Speter 	register struct nl	*p;
35765Speter 	register		*c, *co;
36765Speter 	int			f, o;
37765Speter 	int			tr[2], trp[3];
38765Speter 	struct nl		*firstp;
39765Speter 	struct nl		*lastp;
40765Speter 	char			*firstsymbol;
41765Speter 	int			firstbn;
42765Speter 
43765Speter 	if ( r == NIL ) {
44765Speter 		return NIL;
45765Speter 	}
46765Speter 	if ( nowexp( r ) ) {
47765Speter 		return NIL;
48765Speter 	}
49765Speter 	if ( r[0] != T_VAR ) {
50765Speter 		error("Variable required");	/* Pass mesgs down from pt of call ? */
51765Speter 		return NIL;
52765Speter 	}
53765Speter 	firstp = p = lookup( r[2] );
54765Speter 	if ( p == NIL ) {
55765Speter 		return NIL;
56765Speter 	}
57765Speter 	firstsymbol = p -> symbol;
58765Speter 	firstbn = bn;
59765Speter 	c = r[3];
60765Speter 	if ( ( modflag & NOUSE ) && ! lptr( c ) ) {
61765Speter 		p -> nl_flags = flagwas;
62765Speter 	}
63765Speter 	if ( modflag & MOD ) {
64765Speter 		p -> nl_flags |= NMOD;
65765Speter 	}
66765Speter 	/*
67765Speter 	 * Only possibilities for p -> class here
68765Speter 	 * are the named classes, i.e. CONST, TYPE
69765Speter 	 * VAR, PROC, FUNC, REF, or a WITHPTR.
70765Speter 	 */
71765Speter 	if ( p -> class == WITHPTR ) {
72765Speter 		/*
73765Speter 		 * Construct the tree implied by
74765Speter 		 * the with statement
75765Speter 		 */
76765Speter 	    trp[0] = T_LISTPP;
77765Speter 	    trp[1] = tr;
78765Speter 	    trp[2] = r[3];
79765Speter 	    tr[0] = T_FIELD;
80765Speter 	    tr[1] = r[2];
81765Speter 	    c = trp;
82765Speter 	}
83765Speter 	    /*
84765Speter 	     *	this not only puts out the names of functions to call
85765Speter 	     *	but also does all the semantic checking of the qualifications.
86765Speter 	     */
87765Speter 	if ( ! nilfnil( p , c , modflag , firstp , r[2] ) ) {
88765Speter 	    return NIL;
89765Speter 	}
90765Speter 	switch (p -> class) {
91765Speter 		case WITHPTR:
92765Speter 		case REF:
93765Speter 			/*
94765Speter 			 * Obtain the indirect word
95765Speter 			 * of the WITHPTR or REF
96765Speter 			 * as the base of our lvalue
97765Speter 			 */
98765Speter 			putRV( firstsymbol , firstbn , p -> value[ 0 ]
99765Speter 				    , p2type( p ) );
100765Speter 			firstsymbol = 0;
101765Speter 			f = 0;		/* have an lv on stack */
102765Speter 			o = 0;
103765Speter 			break;
104765Speter 		case VAR:
105765Speter 			f = 1;		/* no lv on stack yet */
106765Speter 			o = p -> value[0];
107765Speter 			break;
108765Speter 		default:
109765Speter 			error("%s %s found where variable required", classes[p -> class], p -> symbol);
110765Speter 			return (NIL);
111765Speter 	}
112765Speter 	/*
113765Speter 	 * Loop and handle each
114765Speter 	 * qualification on the name
115765Speter 	 */
1163375Speter 	if ( c == NIL &&
1173375Speter 	    ( modflag & ASGN ) &&
118*3583Speter 	    ( p -> value[ NL_FORV ] & FORVAR ) ) {
119765Speter 		error("Can't modify the for variable %s in the range of the loop", p -> symbol);
120765Speter 		return (NIL);
121765Speter 	}
122765Speter 	for ( ; c != NIL ; c = c[2] ) {
123765Speter 		co = c[1];
124765Speter 		if ( co == NIL ) {
125765Speter 			return NIL;
126765Speter 		}
127765Speter 		lastp = p;
128765Speter 		p = p -> type;
129765Speter 		if ( p == NIL ) {
130765Speter 			return NIL;
131765Speter 		}
132765Speter 		switch ( co[0] ) {
133765Speter 			case T_PTR:
134765Speter 				/*
135765Speter 				 * Pointer qualification.
136765Speter 				 */
137765Speter 				if ( f ) {
138765Speter 					putLV( firstsymbol , firstbn , o
139765Speter 					       , p2type( p ) );
140765Speter 					firstsymbol = 0;
141765Speter 				} else {
142765Speter 					if (o) {
143765Speter 					    putleaf( P2ICON , o , 0 , P2INT
144765Speter 						    , 0 );
145765Speter 					    putop( P2PLUS , P2PTR | P2CHAR );
146765Speter 					}
147765Speter 				}
148765Speter 				    /*
149765Speter 				     * Pointer cannot be
150765Speter 				     * nil and file cannot
151765Speter 				     * be at end-of-file.
152765Speter 				     * the appropriate function name is
153765Speter 				     * already out there from nilfnil.
154765Speter 				     */
155765Speter 				if ( p -> class == PTR ) {
156765Speter 					/*
157765Speter 					 * this is the indirection from
158765Speter 					 * the address of the pointer
159765Speter 					 * to the pointer itself.
160765Speter 					 * kirk sez:
161765Speter 					 * fnil doesn't want this.
162765Speter 					 * and does it itself for files
163765Speter 					 * since only it knows where the
164765Speter 					 * actual window is.
165765Speter 					 * but i have to do this for
166765Speter 					 * regular pointers.
167765Speter 					 */
168765Speter 				    putop( P2UNARY P2MUL , p2type( p ) );
169765Speter 				    if ( opt( 't' ) ) {
170765Speter 					putop( P2CALL , P2INT );
171765Speter 				    }
172765Speter 				} else {
173765Speter 				    putop( P2CALL , P2INT );
174765Speter 				}
175765Speter 				f = o = 0;
176765Speter 				continue;
177765Speter 			case T_ARGL:
178765Speter 			case T_ARY:
179765Speter 				if ( f ) {
180765Speter 					putLV( firstsymbol , firstbn , o
181765Speter 						, p2type( p ) );
182765Speter 					firstsymbol = 0;
183765Speter 				} else {
184765Speter 					if (o) {
185765Speter 					    putleaf( P2ICON , o , 0 , P2INT
186765Speter 						    , 0 );
187765Speter 					    putop( P2PLUS , P2INT );
188765Speter 					}
189765Speter 				}
190765Speter 				arycod( p , co[1] );
191765Speter 				f = o = 0;
192765Speter 				continue;
193765Speter 			case T_FIELD:
194765Speter 				/*
195765Speter 				 * Field names are just
196765Speter 				 * an offset with some
197765Speter 				 * semantic checking.
198765Speter 				 */
199765Speter 				p = reclook(p, co[1]);
200765Speter 				o += p -> value[0];
201765Speter 				continue;
202765Speter 			default:
203765Speter 				panic("lval2");
204765Speter 		}
205765Speter 	}
206765Speter 	if (f) {
2073375Speter 		if ( required == LREQ ) {
2083375Speter 		    putLV( firstsymbol , firstbn , o , p2type( p -> type ) );
2093375Speter 		} else {
2103375Speter 		    putRV( firstsymbol , firstbn , o , p2type( p -> type ) );
2113375Speter 		}
212765Speter 	} else {
213765Speter 		if (o) {
214765Speter 		    putleaf( P2ICON , o , 0 , P2INT , 0 );
215765Speter 		    putop( P2PLUS , P2INT );
216765Speter 		}
2173375Speter 		if ( required == RREQ ) {
2183375Speter 		    putop( P2UNARY P2MUL , p2type( p -> type ) );
2193375Speter 		}
220765Speter 	}
221765Speter 	return ( p -> type );
222765Speter }
223765Speter 
224765Speter     /*
225765Speter      *	this recursively follows done a list of qualifications
226765Speter      *	and puts out the beginnings of calls to fnil for files
227765Speter      *	or nil for pointers (if checking is on) on the way back.
228765Speter      *	this returns true or false.
229765Speter      */
230765Speter nilfnil( p , c , modflag , firstp , r2 )
231765Speter     struct nl	*p;
232765Speter     int		*c;
233765Speter     int		modflag;
234765Speter     struct nl	*firstp;
235765Speter     char	*r2;		/* no, not r2-d2 */
236765Speter     {
237765Speter 	int		*co;
238765Speter 	struct nl	*lastp;
239765Speter 	int		t;
240765Speter 
241765Speter 	if ( c == NIL ) {
242765Speter 	    return TRUE;
243765Speter 	}
244765Speter 	co = (int *) ( c[1] );
245765Speter 	if ( co == NIL ) {
246765Speter 		return FALSE;
247765Speter 	}
248765Speter 	lastp = p;
249765Speter 	p = p -> type;
250765Speter 	if ( p == NIL ) {
251765Speter 		return FALSE;
252765Speter 	}
253765Speter 	switch ( co[0] ) {
254765Speter 	    case T_PTR:
255765Speter 		    /*
256765Speter 		     * Pointer qualification.
257765Speter 		     */
258765Speter 		    lastp -> nl_flags |= NUSED;
259765Speter 		    if ( p -> class != PTR && p -> class != FILET) {
260765Speter 			    error("^ allowed only on files and pointers, not on %ss", nameof(p));
261765Speter 			    goto bad;
262765Speter 		    }
263765Speter 		    break;
264765Speter 	    case T_ARGL:
265765Speter 		    if ( p -> class != ARRAY ) {
266765Speter 			    if ( lastp == firstp ) {
267765Speter 				    error("%s is a %s, not a function", r2, classes[firstp -> class]);
268765Speter 			    } else {
269765Speter 				    error("Illegal function qualificiation");
270765Speter 			    }
271765Speter 			    return FALSE;
272765Speter 		    }
273765Speter 		    recovered();
274765Speter 		    error("Pascal uses [] for subscripting, not ()");
275765Speter 		    /* and fall through */
276765Speter 	    case T_ARY:
277765Speter 		    if ( p -> class != ARRAY ) {
278765Speter 			    error("Subscripting allowed only on arrays, not on %ss", nameof(p));
279765Speter 			    goto bad;
280765Speter 		    }
281765Speter 		    codeoff();
282765Speter 		    t = arycod( p , co[1] );
283765Speter 		    codeon();
284765Speter 		    switch ( t ) {
285765Speter 			    case 0:
286765Speter 				    return FALSE;
287765Speter 			    case -1:
288765Speter 				    goto bad;
289765Speter 		    }
290765Speter 		    break;
291765Speter 	    case T_FIELD:
292765Speter 		    /*
293765Speter 		     * Field names are just
294765Speter 		     * an offset with some
295765Speter 		     * semantic checking.
296765Speter 		     */
297765Speter 		    if ( p -> class != RECORD ) {
298765Speter 			    error(". allowed only on records, not on %ss", nameof(p));
299765Speter 			    goto bad;
300765Speter 		    }
301765Speter 		    if ( co[1] == NIL ) {
302765Speter 			    return FALSE;
303765Speter 		    }
304765Speter 		    p = reclook( p , co[1] );
305765Speter 		    if ( p == NIL ) {
306765Speter 			    error("%s is not a field in this record", co[1]);
307765Speter 			    goto bad;
308765Speter 		    }
309765Speter 		    if ( modflag & MOD ) {
310765Speter 			    p -> nl_flags |= NMOD;
311765Speter 		    }
312765Speter 		    if ( ( modflag & NOUSE ) == 0 || lptr( c[2] ) ) {
313765Speter 			    p -> nl_flags |= NUSED;
314765Speter 		    }
315765Speter 		    break;
316765Speter 	    default:
317765Speter 		    panic("nilfnil");
318765Speter 	}
319765Speter 	    /*
320765Speter 	     *	recursive call, check the rest of the qualifications.
321765Speter 	     */
322765Speter 	if ( ! nilfnil( p , c[2] , modflag , firstp , r2 ) ) {
323765Speter 	    return FALSE;
324765Speter 	}
325765Speter 	    /*
326765Speter 	     *	the point of all this.
327765Speter 	     */
328765Speter 	if ( co[0] == T_PTR ) {
329765Speter 	    if ( p -> class == PTR ) {
330765Speter 		    if ( opt( 't' ) ) {
331765Speter 			putleaf( P2ICON , 0 , 0
332765Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR )
333765Speter 			    , "_NIL" );
334765Speter 		    }
335765Speter 	    } else {
336765Speter 		    putleaf( P2ICON , 0 , 0
337765Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
338765Speter 			, "_FNIL" );
339765Speter 	    }
340765Speter 	}
341765Speter 	return TRUE;
342765Speter bad:
343765Speter 	cerror("Error occurred on qualification of %s", r2);
344765Speter 	return FALSE;
345765Speter     }
346765Speter #endif PC
347