xref: /csrg-svn/usr.bin/pascal/src/pclval.c (revision 62213)
148116Sbostic /*-
2*62213Sbostic  * Copyright (c) 1980, 1993
3*62213Sbostic  *	The Regents of the University of California.  All rights reserved.
448116Sbostic  *
548116Sbostic  * %sccs.include.redist.c%
622184Sdist  */
7765Speter 
814739Sthien #ifndef lint
9*62213Sbostic static char sccsid[] = "@(#)pclval.c	8.1 (Berkeley) 06/06/93";
1048116Sbostic #endif /* not lint */
11765Speter 
12765Speter #include "whoami.h"
13765Speter #include "0.h"
14765Speter #include "tree.h"
15765Speter #include "opcode.h"
16765Speter #include "objfmt.h"
1714739Sthien #include "tree_ty.h"
18765Speter #ifdef PC
19765Speter 	/*
20765Speter 	 *	and the rest of the file
21765Speter 	 */
22765Speter #   include	"pc.h"
2318465Sralph #   include	<pcc.h>
24765Speter 
25765Speter extern	int flagwas;
26765Speter /*
27765Speter  * pclvalue computes the address
28765Speter  * of a qualified name and
29765Speter  * leaves it on the stack.
30765Speter  * for pc, it can be asked for either an lvalue or an rvalue.
31765Speter  * the semantics are the same, only the code is different.
32765Speter  * for putting out calls to check for nil and fnil,
33765Speter  * we have to traverse the list of qualifications twice:
34765Speter  * once to put out the calls and once to put out the address to be checked.
35765Speter  */
36765Speter struct nl *
pclvalue(var,modflag,required)3714739Sthien pclvalue( var , modflag , required )
3814739Sthien 	struct tnode	*var;
39765Speter 	int	modflag;
40765Speter 	int	required;
41765Speter {
42765Speter 	register struct nl	*p;
4314739Sthien 	register struct tnode 	*c, *co;
44765Speter 	int			f, o;
4514739Sthien 	struct tnode		l_node, tr;
4614739Sthien 	VAR_NODE		*v_node;
4714739Sthien 	LIST_NODE		*tr_ptr;
4815965Smckusick 	struct nl		*firstp, *lastp;
49765Speter 	char			*firstsymbol;
503832Speter 	char			firstextra_flags;
51765Speter 	int			firstbn;
5215965Smckusick 	int			s;
53765Speter 
5414739Sthien 	if ( var == TR_NIL ) {
5514739Sthien 		return NLNIL;
56765Speter 	}
5714739Sthien 	if ( nowexp( var ) ) {
5814739Sthien 		return NLNIL;
59765Speter 	}
6014739Sthien 	if ( var->tag != T_VAR ) {
61765Speter 		error("Variable required");	/* Pass mesgs down from pt of call ? */
6214739Sthien 		return NLNIL;
63765Speter 	}
6414739Sthien 	v_node = &(var->var_node);
6514739Sthien 	firstp = p = lookup( v_node->cptr );
6614739Sthien 	if ( p == NLNIL ) {
6714739Sthien 		return NLNIL;
68765Speter 	}
69765Speter 	firstsymbol = p -> symbol;
70765Speter 	firstbn = bn;
713832Speter 	firstextra_flags = p -> extra_flags;
7214739Sthien 	c = v_node->qual;
73765Speter 	if ( ( modflag & NOUSE ) && ! lptr( c ) ) {
74765Speter 		p -> nl_flags = flagwas;
75765Speter 	}
76765Speter 	if ( modflag & MOD ) {
77765Speter 		p -> nl_flags |= NMOD;
78765Speter 	}
79765Speter 	/*
80765Speter 	 * Only possibilities for p -> class here
81765Speter 	 * are the named classes, i.e. CONST, TYPE
82765Speter 	 * VAR, PROC, FUNC, REF, or a WITHPTR.
83765Speter 	 */
8414739Sthien 	 tr_ptr = &(l_node.list_node);
85765Speter 	if ( p -> class == WITHPTR ) {
86765Speter 		/*
87765Speter 		 * Construct the tree implied by
88765Speter 		 * the with statement
89765Speter 		 */
9014739Sthien 	    l_node.tag = T_LISTPP;
9114739Sthien 	    tr_ptr->list = &(tr);
9214739Sthien 	    tr_ptr->next = v_node->qual;
9314739Sthien 	    tr.tag = T_FIELD;
9414739Sthien 	    tr.field_node.id_ptr = v_node->cptr;
9514739Sthien 	    c = &(l_node);
96765Speter 	}
97765Speter 	    /*
98765Speter 	     *	this not only puts out the names of functions to call
99765Speter 	     *	but also does all the semantic checking of the qualifications.
100765Speter 	     */
10114739Sthien 	if ( ! nilfnil( p , c , modflag , firstp , v_node->cptr ) ) {
10214739Sthien 	    return NLNIL;
103765Speter 	}
104765Speter 	switch (p -> class) {
105765Speter 		case WITHPTR:
106765Speter 		case REF:
107765Speter 			/*
108765Speter 			 * Obtain the indirect word
109765Speter 			 * of the WITHPTR or REF
110765Speter 			 * as the base of our lvalue
111765Speter 			 */
1123832Speter 			putRV( firstsymbol , firstbn , p -> value[ 0 ] ,
1133832Speter 				firstextra_flags , p2type( p ) );
114765Speter 			firstsymbol = 0;
115765Speter 			f = 0;		/* have an lv on stack */
116765Speter 			o = 0;
117765Speter 			break;
118765Speter 		case VAR:
11915965Smckusick 			if (p->type->class != CRANGE) {
12015965Smckusick 				f = 1;		/* no lv on stack yet */
12115965Smckusick 				o = p -> value[0];
12215965Smckusick 			} else {
12315965Smckusick 				error("Conformant array bound %s found where variable required", p->symbol);
12415965Smckusick 				return(NIL);
12515965Smckusick 			}
126765Speter 			break;
127765Speter 		default:
128765Speter 			error("%s %s found where variable required", classes[p -> class], p -> symbol);
12914739Sthien 			return (NLNIL);
130765Speter 	}
131765Speter 	/*
132765Speter 	 * Loop and handle each
133765Speter 	 * qualification on the name
134765Speter 	 */
1353375Speter 	if ( c == NIL &&
1363375Speter 	    ( modflag & ASGN ) &&
1373583Speter 	    ( p -> value[ NL_FORV ] & FORVAR ) ) {
138765Speter 		error("Can't modify the for variable %s in the range of the loop", p -> symbol);
13914739Sthien 		return (NLNIL);
140765Speter 	}
14115965Smckusick 	s = 0;
14214739Sthien 	for ( ; c != TR_NIL ; c = c->list_node.next ) {
14314739Sthien 		co = c->list_node.list;
14414739Sthien 		if ( co == TR_NIL ) {
14514739Sthien 			return NLNIL;
146765Speter 		}
14715965Smckusick 		lastp = p;
148765Speter 		p = p -> type;
14914739Sthien 		if ( p == NLNIL ) {
15014739Sthien 			return NLNIL;
151765Speter 		}
15215987Saoki 		/*
15315987Saoki 		 * If we haven't seen enough subscripts, and the next
15415987Saoki 		 * qualification isn't array reference, then it's an error.
15515987Saoki 		 */
15615987Saoki 		if (s && co->tag != T_ARY) {
15715987Saoki 			error("Too few subscripts (%d given, %d required)",
15815987Saoki 				s, p->value[0]);
15915987Saoki 		}
16014739Sthien 		switch ( co->tag ) {
161765Speter 			case T_PTR:
162765Speter 				/*
163765Speter 				 * Pointer qualification.
164765Speter 				 */
165765Speter 				if ( f ) {
1663832Speter 					putLV( firstsymbol , firstbn , o ,
1673832Speter 					    firstextra_flags , p2type( p ) );
168765Speter 					firstsymbol = 0;
169765Speter 				} else {
170765Speter 					if (o) {
17118465Sralph 					    putleaf( PCC_ICON , o , 0 , PCCT_INT
17214739Sthien 						    , (char *) 0 );
17318465Sralph 					    putop( PCC_PLUS , PCCTM_PTR | PCCT_CHAR );
174765Speter 					}
175765Speter 				}
176765Speter 				    /*
177765Speter 				     * Pointer cannot be
178765Speter 				     * nil and file cannot
179765Speter 				     * be at end-of-file.
180765Speter 				     * the appropriate function name is
181765Speter 				     * already out there from nilfnil.
182765Speter 				     */
183765Speter 				if ( p -> class == PTR ) {
184765Speter 					/*
185765Speter 					 * this is the indirection from
186765Speter 					 * the address of the pointer
187765Speter 					 * to the pointer itself.
188765Speter 					 * kirk sez:
189765Speter 					 * fnil doesn't want this.
190765Speter 					 * and does it itself for files
191765Speter 					 * since only it knows where the
192765Speter 					 * actual window is.
193765Speter 					 * but i have to do this for
194765Speter 					 * regular pointers.
195765Speter 					 */
19618465Sralph 				    putop( PCCOM_UNARY PCC_MUL , p2type( p ) );
197765Speter 				    if ( opt( 't' ) ) {
19818465Sralph 					putop( PCC_CALL , PCCT_INT );
199765Speter 				    }
200765Speter 				} else {
20118465Sralph 				    putop( PCC_CALL , PCCT_INT );
202765Speter 				}
203765Speter 				f = o = 0;
204765Speter 				continue;
205765Speter 			case T_ARGL:
206765Speter 			case T_ARY:
207765Speter 				if ( f ) {
2083832Speter 					putLV( firstsymbol , firstbn , o ,
2093832Speter 					    firstextra_flags , p2type( p ) );
210765Speter 					firstsymbol = 0;
211765Speter 				} else {
212765Speter 					if (o) {
21318465Sralph 					    putleaf( PCC_ICON , o , 0 , PCCT_INT
21414739Sthien 						    , (char *) 0 );
21518465Sralph 					    putop( PCC_PLUS , PCCT_INT );
216765Speter 					}
217765Speter 				}
21815965Smckusick 				s = arycod( p , co->ary_node.expr_list, s);
21915965Smckusick 				if (s == p->value[0]) {
22015965Smckusick 					s = 0;
22115965Smckusick 				} else {
22215965Smckusick 					p = lastp;
22315965Smckusick 				}
224765Speter 				f = o = 0;
225765Speter 				continue;
226765Speter 			case T_FIELD:
227765Speter 				/*
228765Speter 				 * Field names are just
229765Speter 				 * an offset with some
230765Speter 				 * semantic checking.
231765Speter 				 */
23214739Sthien 				p = reclook(p, co->field_node.id_ptr);
233765Speter 				o += p -> value[0];
234765Speter 				continue;
235765Speter 			default:
236765Speter 				panic("lval2");
237765Speter 		}
238765Speter 	}
23915987Saoki 	if (s) {
24015987Saoki 		error("Too few subscripts (%d given, %d required)",
24115987Saoki 			s, p->type->value[0]);
24215987Saoki 		return NLNIL;
24315987Saoki 	}
244765Speter 	if (f) {
2453375Speter 		if ( required == LREQ ) {
2463832Speter 		    putLV( firstsymbol , firstbn , o ,
2473832Speter 			    firstextra_flags , p2type( p -> type ) );
2483375Speter 		} else {
2493832Speter 		    putRV( firstsymbol , firstbn , o ,
2503832Speter 			    firstextra_flags , p2type( p -> type ) );
2513375Speter 		}
252765Speter 	} else {
253765Speter 		if (o) {
25418465Sralph 		    putleaf( PCC_ICON , o , 0 , PCCT_INT , (char *) 0 );
25518465Sralph 		    putop( PCC_PLUS , PCCT_INT );
256765Speter 		}
2573375Speter 		if ( required == RREQ ) {
25818465Sralph 		    putop( PCCOM_UNARY PCC_MUL , p2type( p -> type ) );
2593375Speter 		}
260765Speter 	}
261765Speter 	return ( p -> type );
262765Speter }
263765Speter 
264765Speter     /*
265765Speter      *	this recursively follows done a list of qualifications
266765Speter      *	and puts out the beginnings of calls to fnil for files
267765Speter      *	or nil for pointers (if checking is on) on the way back.
268765Speter      *	this returns true or false.
269765Speter      */
27014739Sthien bool
nilfnil(p,c,modflag,firstp,r2)271765Speter nilfnil( p , c , modflag , firstp , r2 )
27214739Sthien     struct nl	 *p;
27314739Sthien     struct tnode *c;
274765Speter     int		modflag;
275765Speter     struct nl	*firstp;
276765Speter     char	*r2;		/* no, not r2-d2 */
277765Speter     {
27814739Sthien 	struct tnode 	*co;
279765Speter 	struct nl	*lastp;
280765Speter 	int		t;
28115965Smckusick 	static int	s = 0;
282765Speter 
28314739Sthien 	if ( c == TR_NIL ) {
284765Speter 	    return TRUE;
285765Speter 	}
28614739Sthien 	co = ( c->list_node.list );
28714739Sthien 	if ( co == TR_NIL ) {
288765Speter 		return FALSE;
289765Speter 	}
290765Speter 	lastp = p;
291765Speter 	p = p -> type;
29214739Sthien 	if ( p == NLNIL ) {
293765Speter 		return FALSE;
294765Speter 	}
29514739Sthien 	switch ( co->tag ) {
296765Speter 	    case T_PTR:
297765Speter 		    /*
298765Speter 		     * Pointer qualification.
299765Speter 		     */
300765Speter 		    lastp -> nl_flags |= NUSED;
301765Speter 		    if ( p -> class != PTR && p -> class != FILET) {
302765Speter 			    error("^ allowed only on files and pointers, not on %ss", nameof(p));
303765Speter 			    goto bad;
304765Speter 		    }
305765Speter 		    break;
306765Speter 	    case T_ARGL:
307765Speter 		    if ( p -> class != ARRAY ) {
308765Speter 			    if ( lastp == firstp ) {
309765Speter 				    error("%s is a %s, not a function", r2, classes[firstp -> class]);
310765Speter 			    } else {
311765Speter 				    error("Illegal function qualificiation");
312765Speter 			    }
313765Speter 			    return FALSE;
314765Speter 		    }
315765Speter 		    recovered();
316765Speter 		    error("Pascal uses [] for subscripting, not ()");
317765Speter 		    /* and fall through */
318765Speter 	    case T_ARY:
319765Speter 		    if ( p -> class != ARRAY ) {
320765Speter 			    error("Subscripting allowed only on arrays, not on %ss", nameof(p));
321765Speter 			    goto bad;
322765Speter 		    }
323765Speter 		    codeoff();
32415965Smckusick 		    s = arycod( p , co->ary_node.expr_list , s );
325765Speter 		    codeon();
32615965Smckusick 		    switch ( s ) {
327765Speter 			    case 0:
328765Speter 				    return FALSE;
329765Speter 			    case -1:
330765Speter 				    goto bad;
331765Speter 		    }
33215965Smckusick 		    if (s == p->value[0]) {
33315965Smckusick 			    s = 0;
33415965Smckusick 		    } else {
33515965Smckusick 			    p = lastp;
33615965Smckusick 		    }
337765Speter 		    break;
338765Speter 	    case T_FIELD:
339765Speter 		    /*
340765Speter 		     * Field names are just
341765Speter 		     * an offset with some
342765Speter 		     * semantic checking.
343765Speter 		     */
344765Speter 		    if ( p -> class != RECORD ) {
345765Speter 			    error(". allowed only on records, not on %ss", nameof(p));
346765Speter 			    goto bad;
347765Speter 		    }
34814739Sthien 		    if ( co->field_node.id_ptr == NIL ) {
349765Speter 			    return FALSE;
350765Speter 		    }
35114739Sthien 		    p = reclook( p , co->field_node.id_ptr );
352765Speter 		    if ( p == NIL ) {
35314739Sthien 			    error("%s is not a field in this record", co->field_node.id_ptr);
354765Speter 			    goto bad;
355765Speter 		    }
356765Speter 		    if ( modflag & MOD ) {
357765Speter 			    p -> nl_flags |= NMOD;
358765Speter 		    }
35914739Sthien 		    if ((modflag & NOUSE) == 0 || lptr(c->field_node.other )) {
360765Speter 			    p -> nl_flags |= NUSED;
361765Speter 		    }
362765Speter 		    break;
363765Speter 	    default:
364765Speter 		    panic("nilfnil");
365765Speter 	}
366765Speter 	    /*
367765Speter 	     *	recursive call, check the rest of the qualifications.
368765Speter 	     */
36914739Sthien 	if ( ! nilfnil( p , c->list_node.next , modflag , firstp , r2 ) ) {
370765Speter 	    return FALSE;
371765Speter 	}
372765Speter 	    /*
373765Speter 	     *	the point of all this.
374765Speter 	     */
37514739Sthien 	if ( co->tag == T_PTR ) {
376765Speter 	    if ( p -> class == PTR ) {
377765Speter 		    if ( opt( 't' ) ) {
37818465Sralph 			putleaf( PCC_ICON , 0 , 0
37918465Sralph 			    , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
380765Speter 			    , "_NIL" );
381765Speter 		    }
382765Speter 	    } else {
38318465Sralph 		    putleaf( PCC_ICON , 0 , 0
38418465Sralph 			, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
385765Speter 			, "_FNIL" );
386765Speter 	    }
387765Speter 	}
388765Speter 	return TRUE;
389765Speter bad:
390765Speter 	cerror("Error occurred on qualification of %s", r2);
391765Speter 	return FALSE;
392765Speter     }
393765Speter #endif PC
394