xref: /csrg-svn/usr.bin/pascal/src/pclval.c (revision 18465)
1765Speter /* Copyright (c) 1979 Regents of the University of California */
2765Speter 
314739Sthien #ifndef lint
4*18465Sralph static	char sccsid[] = "@(#)pclval.c 2.2 03/20/85";
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"
18*18465Sralph #   include	<pcc.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;
4315965Smckusick 	struct nl		*firstp, *lastp;
44765Speter 	char			*firstsymbol;
453832Speter 	char			firstextra_flags;
46765Speter 	int			firstbn;
4715965Smckusick 	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:
11415965Smckusick 			if (p->type->class != CRANGE) {
11515965Smckusick 				f = 1;		/* no lv on stack yet */
11615965Smckusick 				o = p -> value[0];
11715965Smckusick 			} else {
11815965Smckusick 				error("Conformant array bound %s found where variable required", p->symbol);
11915965Smckusick 				return(NIL);
12015965Smckusick 			}
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 	}
13615965Smckusick 	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 		}
14215965Smckusick 		lastp = p;
143765Speter 		p = p -> type;
14414739Sthien 		if ( p == NLNIL ) {
14514739Sthien 			return NLNIL;
146765Speter 		}
14715987Saoki 		/*
14815987Saoki 		 * If we haven't seen enough subscripts, and the next
14915987Saoki 		 * qualification isn't array reference, then it's an error.
15015987Saoki 		 */
15115987Saoki 		if (s && co->tag != T_ARY) {
15215987Saoki 			error("Too few subscripts (%d given, %d required)",
15315987Saoki 				s, p->value[0]);
15415987Saoki 		}
15514739Sthien 		switch ( co->tag ) {
156765Speter 			case T_PTR:
157765Speter 				/*
158765Speter 				 * Pointer qualification.
159765Speter 				 */
160765Speter 				if ( f ) {
1613832Speter 					putLV( firstsymbol , firstbn , o ,
1623832Speter 					    firstextra_flags , p2type( p ) );
163765Speter 					firstsymbol = 0;
164765Speter 				} else {
165765Speter 					if (o) {
166*18465Sralph 					    putleaf( PCC_ICON , o , 0 , PCCT_INT
16714739Sthien 						    , (char *) 0 );
168*18465Sralph 					    putop( PCC_PLUS , PCCTM_PTR | PCCT_CHAR );
169765Speter 					}
170765Speter 				}
171765Speter 				    /*
172765Speter 				     * Pointer cannot be
173765Speter 				     * nil and file cannot
174765Speter 				     * be at end-of-file.
175765Speter 				     * the appropriate function name is
176765Speter 				     * already out there from nilfnil.
177765Speter 				     */
178765Speter 				if ( p -> class == PTR ) {
179765Speter 					/*
180765Speter 					 * this is the indirection from
181765Speter 					 * the address of the pointer
182765Speter 					 * to the pointer itself.
183765Speter 					 * kirk sez:
184765Speter 					 * fnil doesn't want this.
185765Speter 					 * and does it itself for files
186765Speter 					 * since only it knows where the
187765Speter 					 * actual window is.
188765Speter 					 * but i have to do this for
189765Speter 					 * regular pointers.
190765Speter 					 */
191*18465Sralph 				    putop( PCCOM_UNARY PCC_MUL , p2type( p ) );
192765Speter 				    if ( opt( 't' ) ) {
193*18465Sralph 					putop( PCC_CALL , PCCT_INT );
194765Speter 				    }
195765Speter 				} else {
196*18465Sralph 				    putop( PCC_CALL , PCCT_INT );
197765Speter 				}
198765Speter 				f = o = 0;
199765Speter 				continue;
200765Speter 			case T_ARGL:
201765Speter 			case T_ARY:
202765Speter 				if ( f ) {
2033832Speter 					putLV( firstsymbol , firstbn , o ,
2043832Speter 					    firstextra_flags , p2type( p ) );
205765Speter 					firstsymbol = 0;
206765Speter 				} else {
207765Speter 					if (o) {
208*18465Sralph 					    putleaf( PCC_ICON , o , 0 , PCCT_INT
20914739Sthien 						    , (char *) 0 );
210*18465Sralph 					    putop( PCC_PLUS , PCCT_INT );
211765Speter 					}
212765Speter 				}
21315965Smckusick 				s = arycod( p , co->ary_node.expr_list, s);
21415965Smckusick 				if (s == p->value[0]) {
21515965Smckusick 					s = 0;
21615965Smckusick 				} else {
21715965Smckusick 					p = lastp;
21815965Smckusick 				}
219765Speter 				f = o = 0;
220765Speter 				continue;
221765Speter 			case T_FIELD:
222765Speter 				/*
223765Speter 				 * Field names are just
224765Speter 				 * an offset with some
225765Speter 				 * semantic checking.
226765Speter 				 */
22714739Sthien 				p = reclook(p, co->field_node.id_ptr);
228765Speter 				o += p -> value[0];
229765Speter 				continue;
230765Speter 			default:
231765Speter 				panic("lval2");
232765Speter 		}
233765Speter 	}
23415987Saoki 	if (s) {
23515987Saoki 		error("Too few subscripts (%d given, %d required)",
23615987Saoki 			s, p->type->value[0]);
23715987Saoki 		return NLNIL;
23815987Saoki 	}
239765Speter 	if (f) {
2403375Speter 		if ( required == LREQ ) {
2413832Speter 		    putLV( firstsymbol , firstbn , o ,
2423832Speter 			    firstextra_flags , p2type( p -> type ) );
2433375Speter 		} else {
2443832Speter 		    putRV( firstsymbol , firstbn , o ,
2453832Speter 			    firstextra_flags , p2type( p -> type ) );
2463375Speter 		}
247765Speter 	} else {
248765Speter 		if (o) {
249*18465Sralph 		    putleaf( PCC_ICON , o , 0 , PCCT_INT , (char *) 0 );
250*18465Sralph 		    putop( PCC_PLUS , PCCT_INT );
251765Speter 		}
2523375Speter 		if ( required == RREQ ) {
253*18465Sralph 		    putop( PCCOM_UNARY PCC_MUL , p2type( p -> type ) );
2543375Speter 		}
255765Speter 	}
256765Speter 	return ( p -> type );
257765Speter }
258765Speter 
259765Speter     /*
260765Speter      *	this recursively follows done a list of qualifications
261765Speter      *	and puts out the beginnings of calls to fnil for files
262765Speter      *	or nil for pointers (if checking is on) on the way back.
263765Speter      *	this returns true or false.
264765Speter      */
26514739Sthien bool
266765Speter nilfnil( p , c , modflag , firstp , r2 )
26714739Sthien     struct nl	 *p;
26814739Sthien     struct tnode *c;
269765Speter     int		modflag;
270765Speter     struct nl	*firstp;
271765Speter     char	*r2;		/* no, not r2-d2 */
272765Speter     {
27314739Sthien 	struct tnode 	*co;
274765Speter 	struct nl	*lastp;
275765Speter 	int		t;
27615965Smckusick 	static int	s = 0;
277765Speter 
27814739Sthien 	if ( c == TR_NIL ) {
279765Speter 	    return TRUE;
280765Speter 	}
28114739Sthien 	co = ( c->list_node.list );
28214739Sthien 	if ( co == TR_NIL ) {
283765Speter 		return FALSE;
284765Speter 	}
285765Speter 	lastp = p;
286765Speter 	p = p -> type;
28714739Sthien 	if ( p == NLNIL ) {
288765Speter 		return FALSE;
289765Speter 	}
29014739Sthien 	switch ( co->tag ) {
291765Speter 	    case T_PTR:
292765Speter 		    /*
293765Speter 		     * Pointer qualification.
294765Speter 		     */
295765Speter 		    lastp -> nl_flags |= NUSED;
296765Speter 		    if ( p -> class != PTR && p -> class != FILET) {
297765Speter 			    error("^ allowed only on files and pointers, not on %ss", nameof(p));
298765Speter 			    goto bad;
299765Speter 		    }
300765Speter 		    break;
301765Speter 	    case T_ARGL:
302765Speter 		    if ( p -> class != ARRAY ) {
303765Speter 			    if ( lastp == firstp ) {
304765Speter 				    error("%s is a %s, not a function", r2, classes[firstp -> class]);
305765Speter 			    } else {
306765Speter 				    error("Illegal function qualificiation");
307765Speter 			    }
308765Speter 			    return FALSE;
309765Speter 		    }
310765Speter 		    recovered();
311765Speter 		    error("Pascal uses [] for subscripting, not ()");
312765Speter 		    /* and fall through */
313765Speter 	    case T_ARY:
314765Speter 		    if ( p -> class != ARRAY ) {
315765Speter 			    error("Subscripting allowed only on arrays, not on %ss", nameof(p));
316765Speter 			    goto bad;
317765Speter 		    }
318765Speter 		    codeoff();
31915965Smckusick 		    s = arycod( p , co->ary_node.expr_list , s );
320765Speter 		    codeon();
32115965Smckusick 		    switch ( s ) {
322765Speter 			    case 0:
323765Speter 				    return FALSE;
324765Speter 			    case -1:
325765Speter 				    goto bad;
326765Speter 		    }
32715965Smckusick 		    if (s == p->value[0]) {
32815965Smckusick 			    s = 0;
32915965Smckusick 		    } else {
33015965Smckusick 			    p = lastp;
33115965Smckusick 		    }
332765Speter 		    break;
333765Speter 	    case T_FIELD:
334765Speter 		    /*
335765Speter 		     * Field names are just
336765Speter 		     * an offset with some
337765Speter 		     * semantic checking.
338765Speter 		     */
339765Speter 		    if ( p -> class != RECORD ) {
340765Speter 			    error(". allowed only on records, not on %ss", nameof(p));
341765Speter 			    goto bad;
342765Speter 		    }
34314739Sthien 		    if ( co->field_node.id_ptr == NIL ) {
344765Speter 			    return FALSE;
345765Speter 		    }
34614739Sthien 		    p = reclook( p , co->field_node.id_ptr );
347765Speter 		    if ( p == NIL ) {
34814739Sthien 			    error("%s is not a field in this record", co->field_node.id_ptr);
349765Speter 			    goto bad;
350765Speter 		    }
351765Speter 		    if ( modflag & MOD ) {
352765Speter 			    p -> nl_flags |= NMOD;
353765Speter 		    }
35414739Sthien 		    if ((modflag & NOUSE) == 0 || lptr(c->field_node.other )) {
355765Speter 			    p -> nl_flags |= NUSED;
356765Speter 		    }
357765Speter 		    break;
358765Speter 	    default:
359765Speter 		    panic("nilfnil");
360765Speter 	}
361765Speter 	    /*
362765Speter 	     *	recursive call, check the rest of the qualifications.
363765Speter 	     */
36414739Sthien 	if ( ! nilfnil( p , c->list_node.next , modflag , firstp , r2 ) ) {
365765Speter 	    return FALSE;
366765Speter 	}
367765Speter 	    /*
368765Speter 	     *	the point of all this.
369765Speter 	     */
37014739Sthien 	if ( co->tag == T_PTR ) {
371765Speter 	    if ( p -> class == PTR ) {
372765Speter 		    if ( opt( 't' ) ) {
373*18465Sralph 			putleaf( PCC_ICON , 0 , 0
374*18465Sralph 			    , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
375765Speter 			    , "_NIL" );
376765Speter 		    }
377765Speter 	    } else {
378*18465Sralph 		    putleaf( PCC_ICON , 0 , 0
379*18465Sralph 			, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
380765Speter 			, "_FNIL" );
381765Speter 	    }
382765Speter 	}
383765Speter 	return TRUE;
384765Speter bad:
385765Speter 	cerror("Error occurred on qualification of %s", r2);
386765Speter 	return FALSE;
387765Speter     }
388765Speter #endif PC
389