xref: /csrg-svn/usr.bin/pascal/src/pclval.c (revision 14739)
1765Speter /* Copyright (c) 1979 Regents of the University of California */
2765Speter 
3*14739Sthien #ifndef lint
4*14739Sthien static	char sccsid[] = "@(#)pclval.c 1.5 08/19/83";
5*14739Sthien #endif
6765Speter 
7765Speter #include "whoami.h"
8765Speter #include "0.h"
9765Speter #include "tree.h"
10765Speter #include "opcode.h"
11765Speter #include "objfmt.h"
12*14739Sthien #include "tree_ty.h"
13765Speter #ifdef PC
14765Speter 	/*
15765Speter 	 *	and the rest of the file
16765Speter 	 */
17765Speter #   include	"pc.h"
18765Speter #   include	"pcops.h"
19765Speter 
20765Speter extern	int flagwas;
21765Speter /*
22765Speter  * pclvalue computes the address
23765Speter  * of a qualified name and
24765Speter  * leaves it on the stack.
25765Speter  * for pc, it can be asked for either an lvalue or an rvalue.
26765Speter  * the semantics are the same, only the code is different.
27765Speter  * for putting out calls to check for nil and fnil,
28765Speter  * we have to traverse the list of qualifications twice:
29765Speter  * once to put out the calls and once to put out the address to be checked.
30765Speter  */
31765Speter struct nl *
32*14739Sthien pclvalue( var , modflag , required )
33*14739Sthien 	struct tnode	*var;
34765Speter 	int	modflag;
35765Speter 	int	required;
36765Speter {
37765Speter 	register struct nl	*p;
38*14739Sthien 	register struct tnode 	*c, *co;
39765Speter 	int			f, o;
40*14739Sthien 	struct tnode		l_node, tr;
41*14739Sthien 	VAR_NODE		*v_node;
42*14739Sthien 	LIST_NODE		*tr_ptr;
43*14739Sthien 	struct nl		*firstp, *lastp;
44765Speter 	char			*firstsymbol;
453832Speter 	char			firstextra_flags;
46765Speter 	int			firstbn;
47765Speter 
48*14739Sthien 	if ( var == TR_NIL ) {
49*14739Sthien 		return NLNIL;
50765Speter 	}
51*14739Sthien 	if ( nowexp( var ) ) {
52*14739Sthien 		return NLNIL;
53765Speter 	}
54*14739Sthien 	if ( var->tag != T_VAR ) {
55765Speter 		error("Variable required");	/* Pass mesgs down from pt of call ? */
56*14739Sthien 		return NLNIL;
57765Speter 	}
58*14739Sthien 	v_node = &(var->var_node);
59*14739Sthien 	firstp = p = lookup( v_node->cptr );
60*14739Sthien 	if ( p == NLNIL ) {
61*14739Sthien 		return NLNIL;
62765Speter 	}
63765Speter 	firstsymbol = p -> symbol;
64765Speter 	firstbn = bn;
653832Speter 	firstextra_flags = p -> extra_flags;
66*14739Sthien 	c = v_node->qual;
67765Speter 	if ( ( modflag & NOUSE ) && ! lptr( c ) ) {
68765Speter 		p -> nl_flags = flagwas;
69765Speter 	}
70765Speter 	if ( modflag & MOD ) {
71765Speter 		p -> nl_flags |= NMOD;
72765Speter 	}
73765Speter 	/*
74765Speter 	 * Only possibilities for p -> class here
75765Speter 	 * are the named classes, i.e. CONST, TYPE
76765Speter 	 * VAR, PROC, FUNC, REF, or a WITHPTR.
77765Speter 	 */
78*14739Sthien 	 tr_ptr = &(l_node.list_node);
79765Speter 	if ( p -> class == WITHPTR ) {
80765Speter 		/*
81765Speter 		 * Construct the tree implied by
82765Speter 		 * the with statement
83765Speter 		 */
84*14739Sthien 	    l_node.tag = T_LISTPP;
85*14739Sthien 	    tr_ptr->list = &(tr);
86*14739Sthien 	    tr_ptr->next = v_node->qual;
87*14739Sthien 	    tr.tag = T_FIELD;
88*14739Sthien 	    tr.field_node.id_ptr = v_node->cptr;
89*14739Sthien 	    c = &(l_node);
90765Speter 	}
91765Speter 	    /*
92765Speter 	     *	this not only puts out the names of functions to call
93765Speter 	     *	but also does all the semantic checking of the qualifications.
94765Speter 	     */
95*14739Sthien 	if ( ! nilfnil( p , c , modflag , firstp , v_node->cptr ) ) {
96*14739Sthien 	    return NLNIL;
97765Speter 	}
98765Speter 	switch (p -> class) {
99765Speter 		case WITHPTR:
100765Speter 		case REF:
101765Speter 			/*
102765Speter 			 * Obtain the indirect word
103765Speter 			 * of the WITHPTR or REF
104765Speter 			 * as the base of our lvalue
105765Speter 			 */
1063832Speter 			putRV( firstsymbol , firstbn , p -> value[ 0 ] ,
1073832Speter 				firstextra_flags , p2type( p ) );
108765Speter 			firstsymbol = 0;
109765Speter 			f = 0;		/* have an lv on stack */
110765Speter 			o = 0;
111765Speter 			break;
112765Speter 		case VAR:
113765Speter 			f = 1;		/* no lv on stack yet */
114765Speter 			o = p -> value[0];
115765Speter 			break;
116765Speter 		default:
117765Speter 			error("%s %s found where variable required", classes[p -> class], p -> symbol);
118*14739Sthien 			return (NLNIL);
119765Speter 	}
120765Speter 	/*
121765Speter 	 * Loop and handle each
122765Speter 	 * qualification on the name
123765Speter 	 */
1243375Speter 	if ( c == NIL &&
1253375Speter 	    ( modflag & ASGN ) &&
1263583Speter 	    ( p -> value[ NL_FORV ] & FORVAR ) ) {
127765Speter 		error("Can't modify the for variable %s in the range of the loop", p -> symbol);
128*14739Sthien 		return (NLNIL);
129765Speter 	}
130*14739Sthien 	for ( ; c != TR_NIL ; c = c->list_node.next ) {
131*14739Sthien 		co = c->list_node.list;
132*14739Sthien 		if ( co == TR_NIL ) {
133*14739Sthien 			return NLNIL;
134765Speter 		}
135765Speter 		lastp = p;
136765Speter 		p = p -> type;
137*14739Sthien 		if ( p == NLNIL ) {
138*14739Sthien 			return NLNIL;
139765Speter 		}
140*14739Sthien 		switch ( co->tag ) {
141765Speter 			case T_PTR:
142765Speter 				/*
143765Speter 				 * Pointer qualification.
144765Speter 				 */
145765Speter 				if ( f ) {
1463832Speter 					putLV( firstsymbol , firstbn , o ,
1473832Speter 					    firstextra_flags , p2type( p ) );
148765Speter 					firstsymbol = 0;
149765Speter 				} else {
150765Speter 					if (o) {
151765Speter 					    putleaf( P2ICON , o , 0 , P2INT
152*14739Sthien 						    , (char *) 0 );
153765Speter 					    putop( P2PLUS , P2PTR | P2CHAR );
154765Speter 					}
155765Speter 				}
156765Speter 				    /*
157765Speter 				     * Pointer cannot be
158765Speter 				     * nil and file cannot
159765Speter 				     * be at end-of-file.
160765Speter 				     * the appropriate function name is
161765Speter 				     * already out there from nilfnil.
162765Speter 				     */
163765Speter 				if ( p -> class == PTR ) {
164765Speter 					/*
165765Speter 					 * this is the indirection from
166765Speter 					 * the address of the pointer
167765Speter 					 * to the pointer itself.
168765Speter 					 * kirk sez:
169765Speter 					 * fnil doesn't want this.
170765Speter 					 * and does it itself for files
171765Speter 					 * since only it knows where the
172765Speter 					 * actual window is.
173765Speter 					 * but i have to do this for
174765Speter 					 * regular pointers.
175765Speter 					 */
176765Speter 				    putop( P2UNARY P2MUL , p2type( p ) );
177765Speter 				    if ( opt( 't' ) ) {
178765Speter 					putop( P2CALL , P2INT );
179765Speter 				    }
180765Speter 				} else {
181765Speter 				    putop( P2CALL , P2INT );
182765Speter 				}
183765Speter 				f = o = 0;
184765Speter 				continue;
185765Speter 			case T_ARGL:
186765Speter 			case T_ARY:
187765Speter 				if ( f ) {
1883832Speter 					putLV( firstsymbol , firstbn , o ,
1893832Speter 					    firstextra_flags , p2type( p ) );
190765Speter 					firstsymbol = 0;
191765Speter 				} else {
192765Speter 					if (o) {
193765Speter 					    putleaf( P2ICON , o , 0 , P2INT
194*14739Sthien 						    , (char *) 0 );
195765Speter 					    putop( P2PLUS , P2INT );
196765Speter 					}
197765Speter 				}
198*14739Sthien 				(void) arycod( p , co->ary_node.expr_list );
199765Speter 				f = o = 0;
200765Speter 				continue;
201765Speter 			case T_FIELD:
202765Speter 				/*
203765Speter 				 * Field names are just
204765Speter 				 * an offset with some
205765Speter 				 * semantic checking.
206765Speter 				 */
207*14739Sthien 				p = reclook(p, co->field_node.id_ptr);
208765Speter 				o += p -> value[0];
209765Speter 				continue;
210765Speter 			default:
211765Speter 				panic("lval2");
212765Speter 		}
213765Speter 	}
214765Speter 	if (f) {
2153375Speter 		if ( required == LREQ ) {
2163832Speter 		    putLV( firstsymbol , firstbn , o ,
2173832Speter 			    firstextra_flags , p2type( p -> type ) );
2183375Speter 		} else {
2193832Speter 		    putRV( firstsymbol , firstbn , o ,
2203832Speter 			    firstextra_flags , p2type( p -> type ) );
2213375Speter 		}
222765Speter 	} else {
223765Speter 		if (o) {
224*14739Sthien 		    putleaf( P2ICON , o , 0 , P2INT , (char *) 0 );
225765Speter 		    putop( P2PLUS , P2INT );
226765Speter 		}
2273375Speter 		if ( required == RREQ ) {
2283375Speter 		    putop( P2UNARY P2MUL , p2type( p -> type ) );
2293375Speter 		}
230765Speter 	}
231765Speter 	return ( p -> type );
232765Speter }
233765Speter 
234765Speter     /*
235765Speter      *	this recursively follows done a list of qualifications
236765Speter      *	and puts out the beginnings of calls to fnil for files
237765Speter      *	or nil for pointers (if checking is on) on the way back.
238765Speter      *	this returns true or false.
239765Speter      */
240*14739Sthien bool
241765Speter nilfnil( p , c , modflag , firstp , r2 )
242*14739Sthien     struct nl	 *p;
243*14739Sthien     struct tnode *c;
244765Speter     int		modflag;
245765Speter     struct nl	*firstp;
246765Speter     char	*r2;		/* no, not r2-d2 */
247765Speter     {
248*14739Sthien 	struct tnode 	*co;
249765Speter 	struct nl	*lastp;
250765Speter 	int		t;
251765Speter 
252*14739Sthien 	if ( c == TR_NIL ) {
253765Speter 	    return TRUE;
254765Speter 	}
255*14739Sthien 	co = ( c->list_node.list );
256*14739Sthien 	if ( co == TR_NIL ) {
257765Speter 		return FALSE;
258765Speter 	}
259765Speter 	lastp = p;
260765Speter 	p = p -> type;
261*14739Sthien 	if ( p == NLNIL ) {
262765Speter 		return FALSE;
263765Speter 	}
264*14739Sthien 	switch ( co->tag ) {
265765Speter 	    case T_PTR:
266765Speter 		    /*
267765Speter 		     * Pointer qualification.
268765Speter 		     */
269765Speter 		    lastp -> nl_flags |= NUSED;
270765Speter 		    if ( p -> class != PTR && p -> class != FILET) {
271765Speter 			    error("^ allowed only on files and pointers, not on %ss", nameof(p));
272765Speter 			    goto bad;
273765Speter 		    }
274765Speter 		    break;
275765Speter 	    case T_ARGL:
276765Speter 		    if ( p -> class != ARRAY ) {
277765Speter 			    if ( lastp == firstp ) {
278765Speter 				    error("%s is a %s, not a function", r2, classes[firstp -> class]);
279765Speter 			    } else {
280765Speter 				    error("Illegal function qualificiation");
281765Speter 			    }
282765Speter 			    return FALSE;
283765Speter 		    }
284765Speter 		    recovered();
285765Speter 		    error("Pascal uses [] for subscripting, not ()");
286765Speter 		    /* and fall through */
287765Speter 	    case T_ARY:
288765Speter 		    if ( p -> class != ARRAY ) {
289765Speter 			    error("Subscripting allowed only on arrays, not on %ss", nameof(p));
290765Speter 			    goto bad;
291765Speter 		    }
292765Speter 		    codeoff();
293*14739Sthien 		    t = arycod( p , co->ary_node.expr_list );
294765Speter 		    codeon();
295765Speter 		    switch ( t ) {
296765Speter 			    case 0:
297765Speter 				    return FALSE;
298765Speter 			    case -1:
299765Speter 				    goto bad;
300765Speter 		    }
301765Speter 		    break;
302765Speter 	    case T_FIELD:
303765Speter 		    /*
304765Speter 		     * Field names are just
305765Speter 		     * an offset with some
306765Speter 		     * semantic checking.
307765Speter 		     */
308765Speter 		    if ( p -> class != RECORD ) {
309765Speter 			    error(". allowed only on records, not on %ss", nameof(p));
310765Speter 			    goto bad;
311765Speter 		    }
312*14739Sthien 		    if ( co->field_node.id_ptr == NIL ) {
313765Speter 			    return FALSE;
314765Speter 		    }
315*14739Sthien 		    p = reclook( p , co->field_node.id_ptr );
316765Speter 		    if ( p == NIL ) {
317*14739Sthien 			    error("%s is not a field in this record", co->field_node.id_ptr);
318765Speter 			    goto bad;
319765Speter 		    }
320765Speter 		    if ( modflag & MOD ) {
321765Speter 			    p -> nl_flags |= NMOD;
322765Speter 		    }
323*14739Sthien 		    if ((modflag & NOUSE) == 0 || lptr(c->field_node.other )) {
324765Speter 			    p -> nl_flags |= NUSED;
325765Speter 		    }
326765Speter 		    break;
327765Speter 	    default:
328765Speter 		    panic("nilfnil");
329765Speter 	}
330765Speter 	    /*
331765Speter 	     *	recursive call, check the rest of the qualifications.
332765Speter 	     */
333*14739Sthien 	if ( ! nilfnil( p , c->list_node.next , modflag , firstp , r2 ) ) {
334765Speter 	    return FALSE;
335765Speter 	}
336765Speter 	    /*
337765Speter 	     *	the point of all this.
338765Speter 	     */
339*14739Sthien 	if ( co->tag == T_PTR ) {
340765Speter 	    if ( p -> class == PTR ) {
341765Speter 		    if ( opt( 't' ) ) {
342765Speter 			putleaf( P2ICON , 0 , 0
343765Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR )
344765Speter 			    , "_NIL" );
345765Speter 		    }
346765Speter 	    } else {
347765Speter 		    putleaf( P2ICON , 0 , 0
348765Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
349765Speter 			, "_FNIL" );
350765Speter 	    }
351765Speter 	}
352765Speter 	return TRUE;
353765Speter bad:
354765Speter 	cerror("Error occurred on qualification of %s", r2);
355765Speter 	return FALSE;
356765Speter     }
357765Speter #endif PC
358