xref: /csrg-svn/usr.bin/pascal/src/pclval.c (revision 3832)
1765Speter /* Copyright (c) 1979 Regents of the University of California */
2765Speter 
3*3832Speter static	char sccsid[] = "@(#)pclval.c 1.4 06/01/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;
41*3832Speter 	char			firstextra_flags;
42765Speter 	int			firstbn;
43765Speter 
44765Speter 	if ( r == NIL ) {
45765Speter 		return NIL;
46765Speter 	}
47765Speter 	if ( nowexp( r ) ) {
48765Speter 		return NIL;
49765Speter 	}
50765Speter 	if ( r[0] != T_VAR ) {
51765Speter 		error("Variable required");	/* Pass mesgs down from pt of call ? */
52765Speter 		return NIL;
53765Speter 	}
54765Speter 	firstp = p = lookup( r[2] );
55765Speter 	if ( p == NIL ) {
56765Speter 		return NIL;
57765Speter 	}
58765Speter 	firstsymbol = p -> symbol;
59765Speter 	firstbn = bn;
60*3832Speter 	firstextra_flags = p -> extra_flags;
61765Speter 	c = r[3];
62765Speter 	if ( ( modflag & NOUSE ) && ! lptr( c ) ) {
63765Speter 		p -> nl_flags = flagwas;
64765Speter 	}
65765Speter 	if ( modflag & MOD ) {
66765Speter 		p -> nl_flags |= NMOD;
67765Speter 	}
68765Speter 	/*
69765Speter 	 * Only possibilities for p -> class here
70765Speter 	 * are the named classes, i.e. CONST, TYPE
71765Speter 	 * VAR, PROC, FUNC, REF, or a WITHPTR.
72765Speter 	 */
73765Speter 	if ( p -> class == WITHPTR ) {
74765Speter 		/*
75765Speter 		 * Construct the tree implied by
76765Speter 		 * the with statement
77765Speter 		 */
78765Speter 	    trp[0] = T_LISTPP;
79765Speter 	    trp[1] = tr;
80765Speter 	    trp[2] = r[3];
81765Speter 	    tr[0] = T_FIELD;
82765Speter 	    tr[1] = r[2];
83765Speter 	    c = trp;
84765Speter 	}
85765Speter 	    /*
86765Speter 	     *	this not only puts out the names of functions to call
87765Speter 	     *	but also does all the semantic checking of the qualifications.
88765Speter 	     */
89765Speter 	if ( ! nilfnil( p , c , modflag , firstp , r[2] ) ) {
90765Speter 	    return NIL;
91765Speter 	}
92765Speter 	switch (p -> class) {
93765Speter 		case WITHPTR:
94765Speter 		case REF:
95765Speter 			/*
96765Speter 			 * Obtain the indirect word
97765Speter 			 * of the WITHPTR or REF
98765Speter 			 * as the base of our lvalue
99765Speter 			 */
100*3832Speter 			putRV( firstsymbol , firstbn , p -> value[ 0 ] ,
101*3832Speter 				firstextra_flags , p2type( p ) );
102765Speter 			firstsymbol = 0;
103765Speter 			f = 0;		/* have an lv on stack */
104765Speter 			o = 0;
105765Speter 			break;
106765Speter 		case VAR:
107765Speter 			f = 1;		/* no lv on stack yet */
108765Speter 			o = p -> value[0];
109765Speter 			break;
110765Speter 		default:
111765Speter 			error("%s %s found where variable required", classes[p -> class], p -> symbol);
112765Speter 			return (NIL);
113765Speter 	}
114765Speter 	/*
115765Speter 	 * Loop and handle each
116765Speter 	 * qualification on the name
117765Speter 	 */
1183375Speter 	if ( c == NIL &&
1193375Speter 	    ( modflag & ASGN ) &&
1203583Speter 	    ( p -> value[ NL_FORV ] & FORVAR ) ) {
121765Speter 		error("Can't modify the for variable %s in the range of the loop", p -> symbol);
122765Speter 		return (NIL);
123765Speter 	}
124765Speter 	for ( ; c != NIL ; c = c[2] ) {
125765Speter 		co = c[1];
126765Speter 		if ( co == NIL ) {
127765Speter 			return NIL;
128765Speter 		}
129765Speter 		lastp = p;
130765Speter 		p = p -> type;
131765Speter 		if ( p == NIL ) {
132765Speter 			return NIL;
133765Speter 		}
134765Speter 		switch ( co[0] ) {
135765Speter 			case T_PTR:
136765Speter 				/*
137765Speter 				 * Pointer qualification.
138765Speter 				 */
139765Speter 				if ( f ) {
140*3832Speter 					putLV( firstsymbol , firstbn , o ,
141*3832Speter 					    firstextra_flags , p2type( p ) );
142765Speter 					firstsymbol = 0;
143765Speter 				} else {
144765Speter 					if (o) {
145765Speter 					    putleaf( P2ICON , o , 0 , P2INT
146765Speter 						    , 0 );
147765Speter 					    putop( P2PLUS , P2PTR | P2CHAR );
148765Speter 					}
149765Speter 				}
150765Speter 				    /*
151765Speter 				     * Pointer cannot be
152765Speter 				     * nil and file cannot
153765Speter 				     * be at end-of-file.
154765Speter 				     * the appropriate function name is
155765Speter 				     * already out there from nilfnil.
156765Speter 				     */
157765Speter 				if ( p -> class == PTR ) {
158765Speter 					/*
159765Speter 					 * this is the indirection from
160765Speter 					 * the address of the pointer
161765Speter 					 * to the pointer itself.
162765Speter 					 * kirk sez:
163765Speter 					 * fnil doesn't want this.
164765Speter 					 * and does it itself for files
165765Speter 					 * since only it knows where the
166765Speter 					 * actual window is.
167765Speter 					 * but i have to do this for
168765Speter 					 * regular pointers.
169765Speter 					 */
170765Speter 				    putop( P2UNARY P2MUL , p2type( p ) );
171765Speter 				    if ( opt( 't' ) ) {
172765Speter 					putop( P2CALL , P2INT );
173765Speter 				    }
174765Speter 				} else {
175765Speter 				    putop( P2CALL , P2INT );
176765Speter 				}
177765Speter 				f = o = 0;
178765Speter 				continue;
179765Speter 			case T_ARGL:
180765Speter 			case T_ARY:
181765Speter 				if ( f ) {
182*3832Speter 					putLV( firstsymbol , firstbn , o ,
183*3832Speter 					    firstextra_flags , p2type( p ) );
184765Speter 					firstsymbol = 0;
185765Speter 				} else {
186765Speter 					if (o) {
187765Speter 					    putleaf( P2ICON , o , 0 , P2INT
188765Speter 						    , 0 );
189765Speter 					    putop( P2PLUS , P2INT );
190765Speter 					}
191765Speter 				}
192765Speter 				arycod( p , co[1] );
193765Speter 				f = o = 0;
194765Speter 				continue;
195765Speter 			case T_FIELD:
196765Speter 				/*
197765Speter 				 * Field names are just
198765Speter 				 * an offset with some
199765Speter 				 * semantic checking.
200765Speter 				 */
201765Speter 				p = reclook(p, co[1]);
202765Speter 				o += p -> value[0];
203765Speter 				continue;
204765Speter 			default:
205765Speter 				panic("lval2");
206765Speter 		}
207765Speter 	}
208765Speter 	if (f) {
2093375Speter 		if ( required == LREQ ) {
210*3832Speter 		    putLV( firstsymbol , firstbn , o ,
211*3832Speter 			    firstextra_flags , p2type( p -> type ) );
2123375Speter 		} else {
213*3832Speter 		    putRV( firstsymbol , firstbn , o ,
214*3832Speter 			    firstextra_flags , p2type( p -> type ) );
2153375Speter 		}
216765Speter 	} else {
217765Speter 		if (o) {
218765Speter 		    putleaf( P2ICON , o , 0 , P2INT , 0 );
219765Speter 		    putop( P2PLUS , P2INT );
220765Speter 		}
2213375Speter 		if ( required == RREQ ) {
2223375Speter 		    putop( P2UNARY P2MUL , p2type( p -> type ) );
2233375Speter 		}
224765Speter 	}
225765Speter 	return ( p -> type );
226765Speter }
227765Speter 
228765Speter     /*
229765Speter      *	this recursively follows done a list of qualifications
230765Speter      *	and puts out the beginnings of calls to fnil for files
231765Speter      *	or nil for pointers (if checking is on) on the way back.
232765Speter      *	this returns true or false.
233765Speter      */
234765Speter nilfnil( p , c , modflag , firstp , r2 )
235765Speter     struct nl	*p;
236765Speter     int		*c;
237765Speter     int		modflag;
238765Speter     struct nl	*firstp;
239765Speter     char	*r2;		/* no, not r2-d2 */
240765Speter     {
241765Speter 	int		*co;
242765Speter 	struct nl	*lastp;
243765Speter 	int		t;
244765Speter 
245765Speter 	if ( c == NIL ) {
246765Speter 	    return TRUE;
247765Speter 	}
248765Speter 	co = (int *) ( c[1] );
249765Speter 	if ( co == NIL ) {
250765Speter 		return FALSE;
251765Speter 	}
252765Speter 	lastp = p;
253765Speter 	p = p -> type;
254765Speter 	if ( p == NIL ) {
255765Speter 		return FALSE;
256765Speter 	}
257765Speter 	switch ( co[0] ) {
258765Speter 	    case T_PTR:
259765Speter 		    /*
260765Speter 		     * Pointer qualification.
261765Speter 		     */
262765Speter 		    lastp -> nl_flags |= NUSED;
263765Speter 		    if ( p -> class != PTR && p -> class != FILET) {
264765Speter 			    error("^ allowed only on files and pointers, not on %ss", nameof(p));
265765Speter 			    goto bad;
266765Speter 		    }
267765Speter 		    break;
268765Speter 	    case T_ARGL:
269765Speter 		    if ( p -> class != ARRAY ) {
270765Speter 			    if ( lastp == firstp ) {
271765Speter 				    error("%s is a %s, not a function", r2, classes[firstp -> class]);
272765Speter 			    } else {
273765Speter 				    error("Illegal function qualificiation");
274765Speter 			    }
275765Speter 			    return FALSE;
276765Speter 		    }
277765Speter 		    recovered();
278765Speter 		    error("Pascal uses [] for subscripting, not ()");
279765Speter 		    /* and fall through */
280765Speter 	    case T_ARY:
281765Speter 		    if ( p -> class != ARRAY ) {
282765Speter 			    error("Subscripting allowed only on arrays, not on %ss", nameof(p));
283765Speter 			    goto bad;
284765Speter 		    }
285765Speter 		    codeoff();
286765Speter 		    t = arycod( p , co[1] );
287765Speter 		    codeon();
288765Speter 		    switch ( t ) {
289765Speter 			    case 0:
290765Speter 				    return FALSE;
291765Speter 			    case -1:
292765Speter 				    goto bad;
293765Speter 		    }
294765Speter 		    break;
295765Speter 	    case T_FIELD:
296765Speter 		    /*
297765Speter 		     * Field names are just
298765Speter 		     * an offset with some
299765Speter 		     * semantic checking.
300765Speter 		     */
301765Speter 		    if ( p -> class != RECORD ) {
302765Speter 			    error(". allowed only on records, not on %ss", nameof(p));
303765Speter 			    goto bad;
304765Speter 		    }
305765Speter 		    if ( co[1] == NIL ) {
306765Speter 			    return FALSE;
307765Speter 		    }
308765Speter 		    p = reclook( p , co[1] );
309765Speter 		    if ( p == NIL ) {
310765Speter 			    error("%s is not a field in this record", co[1]);
311765Speter 			    goto bad;
312765Speter 		    }
313765Speter 		    if ( modflag & MOD ) {
314765Speter 			    p -> nl_flags |= NMOD;
315765Speter 		    }
316765Speter 		    if ( ( modflag & NOUSE ) == 0 || lptr( c[2] ) ) {
317765Speter 			    p -> nl_flags |= NUSED;
318765Speter 		    }
319765Speter 		    break;
320765Speter 	    default:
321765Speter 		    panic("nilfnil");
322765Speter 	}
323765Speter 	    /*
324765Speter 	     *	recursive call, check the rest of the qualifications.
325765Speter 	     */
326765Speter 	if ( ! nilfnil( p , c[2] , modflag , firstp , r2 ) ) {
327765Speter 	    return FALSE;
328765Speter 	}
329765Speter 	    /*
330765Speter 	     *	the point of all this.
331765Speter 	     */
332765Speter 	if ( co[0] == T_PTR ) {
333765Speter 	    if ( p -> class == PTR ) {
334765Speter 		    if ( opt( 't' ) ) {
335765Speter 			putleaf( P2ICON , 0 , 0
336765Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR )
337765Speter 			    , "_NIL" );
338765Speter 		    }
339765Speter 	    } else {
340765Speter 		    putleaf( P2ICON , 0 , 0
341765Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
342765Speter 			, "_FNIL" );
343765Speter 	    }
344765Speter 	}
345765Speter 	return TRUE;
346765Speter bad:
347765Speter 	cerror("Error occurred on qualification of %s", r2);
348765Speter 	return FALSE;
349765Speter     }
350765Speter #endif PC
351