xref: /csrg-svn/usr.bin/pascal/src/pclval.c (revision 15965)
1765Speter /* Copyright (c) 1979 Regents of the University of California */
2765Speter 
314739Sthien #ifndef lint
4*15965Smckusick static	char sccsid[] = "@(#)pclval.c 1.8 02/08/84";
514739Sthien #endif
6765Speter 
7765Speter #include "whoami.h"
8765Speter #include "0.h"
9765Speter #include "tree.h"
10765Speter #include "opcode.h"
11765Speter #include "objfmt.h"
1214739Sthien #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 *
3214739Sthien pclvalue( var , modflag , required )
3314739Sthien 	struct tnode	*var;
34765Speter 	int	modflag;
35765Speter 	int	required;
36765Speter {
37765Speter 	register struct nl	*p;
3814739Sthien 	register struct tnode 	*c, *co;
39765Speter 	int			f, o;
4014739Sthien 	struct tnode		l_node, tr;
4114739Sthien 	VAR_NODE		*v_node;
4214739Sthien 	LIST_NODE		*tr_ptr;
43*15965Smckusick 	struct nl		*firstp, *lastp;
44765Speter 	char			*firstsymbol;
453832Speter 	char			firstextra_flags;
46765Speter 	int			firstbn;
47*15965Smckusick 	int			s;
48765Speter 
4914739Sthien 	if ( var == TR_NIL ) {
5014739Sthien 		return NLNIL;
51765Speter 	}
5214739Sthien 	if ( nowexp( var ) ) {
5314739Sthien 		return NLNIL;
54765Speter 	}
5514739Sthien 	if ( var->tag != T_VAR ) {
56765Speter 		error("Variable required");	/* Pass mesgs down from pt of call ? */
5714739Sthien 		return NLNIL;
58765Speter 	}
5914739Sthien 	v_node = &(var->var_node);
6014739Sthien 	firstp = p = lookup( v_node->cptr );
6114739Sthien 	if ( p == NLNIL ) {
6214739Sthien 		return NLNIL;
63765Speter 	}
64765Speter 	firstsymbol = p -> symbol;
65765Speter 	firstbn = bn;
663832Speter 	firstextra_flags = p -> extra_flags;
6714739Sthien 	c = v_node->qual;
68765Speter 	if ( ( modflag & NOUSE ) && ! lptr( c ) ) {
69765Speter 		p -> nl_flags = flagwas;
70765Speter 	}
71765Speter 	if ( modflag & MOD ) {
72765Speter 		p -> nl_flags |= NMOD;
73765Speter 	}
74765Speter 	/*
75765Speter 	 * Only possibilities for p -> class here
76765Speter 	 * are the named classes, i.e. CONST, TYPE
77765Speter 	 * VAR, PROC, FUNC, REF, or a WITHPTR.
78765Speter 	 */
7914739Sthien 	 tr_ptr = &(l_node.list_node);
80765Speter 	if ( p -> class == WITHPTR ) {
81765Speter 		/*
82765Speter 		 * Construct the tree implied by
83765Speter 		 * the with statement
84765Speter 		 */
8514739Sthien 	    l_node.tag = T_LISTPP;
8614739Sthien 	    tr_ptr->list = &(tr);
8714739Sthien 	    tr_ptr->next = v_node->qual;
8814739Sthien 	    tr.tag = T_FIELD;
8914739Sthien 	    tr.field_node.id_ptr = v_node->cptr;
9014739Sthien 	    c = &(l_node);
91765Speter 	}
92765Speter 	    /*
93765Speter 	     *	this not only puts out the names of functions to call
94765Speter 	     *	but also does all the semantic checking of the qualifications.
95765Speter 	     */
9614739Sthien 	if ( ! nilfnil( p , c , modflag , firstp , v_node->cptr ) ) {
9714739Sthien 	    return NLNIL;
98765Speter 	}
99765Speter 	switch (p -> class) {
100765Speter 		case WITHPTR:
101765Speter 		case REF:
102765Speter 			/*
103765Speter 			 * Obtain the indirect word
104765Speter 			 * of the WITHPTR or REF
105765Speter 			 * as the base of our lvalue
106765Speter 			 */
1073832Speter 			putRV( firstsymbol , firstbn , p -> value[ 0 ] ,
1083832Speter 				firstextra_flags , p2type( p ) );
109765Speter 			firstsymbol = 0;
110765Speter 			f = 0;		/* have an lv on stack */
111765Speter 			o = 0;
112765Speter 			break;
113765Speter 		case VAR:
114*15965Smckusick 			if (p->type->class != CRANGE) {
115*15965Smckusick 				f = 1;		/* no lv on stack yet */
116*15965Smckusick 				o = p -> value[0];
117*15965Smckusick 			} else {
118*15965Smckusick 				error("Conformant array bound %s found where variable required", p->symbol);
119*15965Smckusick 				return(NIL);
120*15965Smckusick 			}
121765Speter 			break;
122765Speter 		default:
123765Speter 			error("%s %s found where variable required", classes[p -> class], p -> symbol);
12414739Sthien 			return (NLNIL);
125765Speter 	}
126765Speter 	/*
127765Speter 	 * Loop and handle each
128765Speter 	 * qualification on the name
129765Speter 	 */
1303375Speter 	if ( c == NIL &&
1313375Speter 	    ( modflag & ASGN ) &&
1323583Speter 	    ( p -> value[ NL_FORV ] & FORVAR ) ) {
133765Speter 		error("Can't modify the for variable %s in the range of the loop", p -> symbol);
13414739Sthien 		return (NLNIL);
135765Speter 	}
136*15965Smckusick 	s = 0;
13714739Sthien 	for ( ; c != TR_NIL ; c = c->list_node.next ) {
13814739Sthien 		co = c->list_node.list;
13914739Sthien 		if ( co == TR_NIL ) {
14014739Sthien 			return NLNIL;
141765Speter 		}
142*15965Smckusick 		lastp = p;
143765Speter 		p = p -> type;
14414739Sthien 		if ( p == NLNIL ) {
14514739Sthien 			return NLNIL;
146765Speter 		}
14714739Sthien 		switch ( co->tag ) {
148765Speter 			case T_PTR:
149765Speter 				/*
150765Speter 				 * Pointer qualification.
151765Speter 				 */
152765Speter 				if ( f ) {
1533832Speter 					putLV( firstsymbol , firstbn , o ,
1543832Speter 					    firstextra_flags , p2type( p ) );
155765Speter 					firstsymbol = 0;
156765Speter 				} else {
157765Speter 					if (o) {
158765Speter 					    putleaf( P2ICON , o , 0 , P2INT
15914739Sthien 						    , (char *) 0 );
160765Speter 					    putop( P2PLUS , P2PTR | P2CHAR );
161765Speter 					}
162765Speter 				}
163765Speter 				    /*
164765Speter 				     * Pointer cannot be
165765Speter 				     * nil and file cannot
166765Speter 				     * be at end-of-file.
167765Speter 				     * the appropriate function name is
168765Speter 				     * already out there from nilfnil.
169765Speter 				     */
170765Speter 				if ( p -> class == PTR ) {
171765Speter 					/*
172765Speter 					 * this is the indirection from
173765Speter 					 * the address of the pointer
174765Speter 					 * to the pointer itself.
175765Speter 					 * kirk sez:
176765Speter 					 * fnil doesn't want this.
177765Speter 					 * and does it itself for files
178765Speter 					 * since only it knows where the
179765Speter 					 * actual window is.
180765Speter 					 * but i have to do this for
181765Speter 					 * regular pointers.
182765Speter 					 */
183765Speter 				    putop( P2UNARY P2MUL , p2type( p ) );
184765Speter 				    if ( opt( 't' ) ) {
185765Speter 					putop( P2CALL , P2INT );
186765Speter 				    }
187765Speter 				} else {
188765Speter 				    putop( P2CALL , P2INT );
189765Speter 				}
190765Speter 				f = o = 0;
191765Speter 				continue;
192765Speter 			case T_ARGL:
193765Speter 			case T_ARY:
194765Speter 				if ( f ) {
1953832Speter 					putLV( firstsymbol , firstbn , o ,
1963832Speter 					    firstextra_flags , p2type( p ) );
197765Speter 					firstsymbol = 0;
198765Speter 				} else {
199765Speter 					if (o) {
200765Speter 					    putleaf( P2ICON , o , 0 , P2INT
20114739Sthien 						    , (char *) 0 );
202765Speter 					    putop( P2PLUS , P2INT );
203765Speter 					}
204765Speter 				}
205*15965Smckusick 				s = arycod( p , co->ary_node.expr_list, s);
206*15965Smckusick 				if (s == p->value[0]) {
207*15965Smckusick 					s = 0;
208*15965Smckusick 				} else {
209*15965Smckusick 					p = lastp;
210*15965Smckusick 				}
211765Speter 				f = o = 0;
212765Speter 				continue;
213765Speter 			case T_FIELD:
214765Speter 				/*
215765Speter 				 * Field names are just
216765Speter 				 * an offset with some
217765Speter 				 * semantic checking.
218765Speter 				 */
21914739Sthien 				p = reclook(p, co->field_node.id_ptr);
220765Speter 				o += p -> value[0];
221765Speter 				continue;
222765Speter 			default:
223765Speter 				panic("lval2");
224765Speter 		}
225765Speter 	}
226765Speter 	if (f) {
2273375Speter 		if ( required == LREQ ) {
2283832Speter 		    putLV( firstsymbol , firstbn , o ,
2293832Speter 			    firstextra_flags , p2type( p -> type ) );
2303375Speter 		} else {
2313832Speter 		    putRV( firstsymbol , firstbn , o ,
2323832Speter 			    firstextra_flags , p2type( p -> type ) );
2333375Speter 		}
234765Speter 	} else {
235765Speter 		if (o) {
23614739Sthien 		    putleaf( P2ICON , o , 0 , P2INT , (char *) 0 );
237765Speter 		    putop( P2PLUS , P2INT );
238765Speter 		}
2393375Speter 		if ( required == RREQ ) {
2403375Speter 		    putop( P2UNARY P2MUL , p2type( p -> type ) );
2413375Speter 		}
242765Speter 	}
243765Speter 	return ( p -> type );
244765Speter }
245765Speter 
246765Speter     /*
247765Speter      *	this recursively follows done a list of qualifications
248765Speter      *	and puts out the beginnings of calls to fnil for files
249765Speter      *	or nil for pointers (if checking is on) on the way back.
250765Speter      *	this returns true or false.
251765Speter      */
25214739Sthien bool
253765Speter nilfnil( p , c , modflag , firstp , r2 )
25414739Sthien     struct nl	 *p;
25514739Sthien     struct tnode *c;
256765Speter     int		modflag;
257765Speter     struct nl	*firstp;
258765Speter     char	*r2;		/* no, not r2-d2 */
259765Speter     {
26014739Sthien 	struct tnode 	*co;
261765Speter 	struct nl	*lastp;
262765Speter 	int		t;
263*15965Smckusick 	static int	s = 0;
264765Speter 
26514739Sthien 	if ( c == TR_NIL ) {
266765Speter 	    return TRUE;
267765Speter 	}
26814739Sthien 	co = ( c->list_node.list );
26914739Sthien 	if ( co == TR_NIL ) {
270765Speter 		return FALSE;
271765Speter 	}
272765Speter 	lastp = p;
273765Speter 	p = p -> type;
27414739Sthien 	if ( p == NLNIL ) {
275765Speter 		return FALSE;
276765Speter 	}
27714739Sthien 	switch ( co->tag ) {
278765Speter 	    case T_PTR:
279765Speter 		    /*
280765Speter 		     * Pointer qualification.
281765Speter 		     */
282765Speter 		    lastp -> nl_flags |= NUSED;
283765Speter 		    if ( p -> class != PTR && p -> class != FILET) {
284765Speter 			    error("^ allowed only on files and pointers, not on %ss", nameof(p));
285765Speter 			    goto bad;
286765Speter 		    }
287765Speter 		    break;
288765Speter 	    case T_ARGL:
289765Speter 		    if ( p -> class != ARRAY ) {
290765Speter 			    if ( lastp == firstp ) {
291765Speter 				    error("%s is a %s, not a function", r2, classes[firstp -> class]);
292765Speter 			    } else {
293765Speter 				    error("Illegal function qualificiation");
294765Speter 			    }
295765Speter 			    return FALSE;
296765Speter 		    }
297765Speter 		    recovered();
298765Speter 		    error("Pascal uses [] for subscripting, not ()");
299765Speter 		    /* and fall through */
300765Speter 	    case T_ARY:
301765Speter 		    if ( p -> class != ARRAY ) {
302765Speter 			    error("Subscripting allowed only on arrays, not on %ss", nameof(p));
303765Speter 			    goto bad;
304765Speter 		    }
305765Speter 		    codeoff();
306*15965Smckusick 		    s = arycod( p , co->ary_node.expr_list , s );
307765Speter 		    codeon();
308*15965Smckusick 		    switch ( s ) {
309765Speter 			    case 0:
310765Speter 				    return FALSE;
311765Speter 			    case -1:
312765Speter 				    goto bad;
313765Speter 		    }
314*15965Smckusick 		    if (s == p->value[0]) {
315*15965Smckusick 			    s = 0;
316*15965Smckusick 		    } else {
317*15965Smckusick 			    p = lastp;
318*15965Smckusick 		    }
319765Speter 		    break;
320765Speter 	    case T_FIELD:
321765Speter 		    /*
322765Speter 		     * Field names are just
323765Speter 		     * an offset with some
324765Speter 		     * semantic checking.
325765Speter 		     */
326765Speter 		    if ( p -> class != RECORD ) {
327765Speter 			    error(". allowed only on records, not on %ss", nameof(p));
328765Speter 			    goto bad;
329765Speter 		    }
33014739Sthien 		    if ( co->field_node.id_ptr == NIL ) {
331765Speter 			    return FALSE;
332765Speter 		    }
33314739Sthien 		    p = reclook( p , co->field_node.id_ptr );
334765Speter 		    if ( p == NIL ) {
33514739Sthien 			    error("%s is not a field in this record", co->field_node.id_ptr);
336765Speter 			    goto bad;
337765Speter 		    }
338765Speter 		    if ( modflag & MOD ) {
339765Speter 			    p -> nl_flags |= NMOD;
340765Speter 		    }
34114739Sthien 		    if ((modflag & NOUSE) == 0 || lptr(c->field_node.other )) {
342765Speter 			    p -> nl_flags |= NUSED;
343765Speter 		    }
344765Speter 		    break;
345765Speter 	    default:
346765Speter 		    panic("nilfnil");
347765Speter 	}
348765Speter 	    /*
349765Speter 	     *	recursive call, check the rest of the qualifications.
350765Speter 	     */
35114739Sthien 	if ( ! nilfnil( p , c->list_node.next , modflag , firstp , r2 ) ) {
352765Speter 	    return FALSE;
353765Speter 	}
354765Speter 	    /*
355765Speter 	     *	the point of all this.
356765Speter 	     */
35714739Sthien 	if ( co->tag == T_PTR ) {
358765Speter 	    if ( p -> class == PTR ) {
359765Speter 		    if ( opt( 't' ) ) {
360765Speter 			putleaf( P2ICON , 0 , 0
361765Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR )
362765Speter 			    , "_NIL" );
363765Speter 		    }
364765Speter 	    } else {
365765Speter 		    putleaf( P2ICON , 0 , 0
366765Speter 			, ADDTYPE( P2FTN | P2INT , P2PTR )
367765Speter 			, "_FNIL" );
368765Speter 	    }
369765Speter 	}
370765Speter 	return TRUE;
371765Speter bad:
372765Speter 	cerror("Error occurred on qualification of %s", r2);
373765Speter 	return FALSE;
374765Speter     }
375765Speter #endif PC
376