xref: /original-bsd/usr.bin/pascal/src/pclval.c (revision b4971bb3)
1 /*-
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)pclval.c	8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11 
12 #include "whoami.h"
13 #include "0.h"
14 #include "tree.h"
15 #include "opcode.h"
16 #include "objfmt.h"
17 #include "tree_ty.h"
18 #ifdef PC
19 	/*
20 	 *	and the rest of the file
21 	 */
22 #   include	"pc.h"
23 #   include	<pcc.h>
24 
25 extern	int flagwas;
26 /*
27  * pclvalue computes the address
28  * of a qualified name and
29  * leaves it on the stack.
30  * for pc, it can be asked for either an lvalue or an rvalue.
31  * the semantics are the same, only the code is different.
32  * for putting out calls to check for nil and fnil,
33  * we have to traverse the list of qualifications twice:
34  * once to put out the calls and once to put out the address to be checked.
35  */
36 struct nl *
37 pclvalue( var , modflag , required )
38 	struct tnode	*var;
39 	int	modflag;
40 	int	required;
41 {
42 	register struct nl	*p;
43 	register struct tnode 	*c, *co;
44 	int			f, o;
45 	struct tnode		l_node, tr;
46 	VAR_NODE		*v_node;
47 	LIST_NODE		*tr_ptr;
48 	struct nl		*firstp, *lastp;
49 	char			*firstsymbol;
50 	char			firstextra_flags;
51 	int			firstbn;
52 	int			s;
53 
54 	if ( var == TR_NIL ) {
55 		return NLNIL;
56 	}
57 	if ( nowexp( var ) ) {
58 		return NLNIL;
59 	}
60 	if ( var->tag != T_VAR ) {
61 		error("Variable required");	/* Pass mesgs down from pt of call ? */
62 		return NLNIL;
63 	}
64 	v_node = &(var->var_node);
65 	firstp = p = lookup( v_node->cptr );
66 	if ( p == NLNIL ) {
67 		return NLNIL;
68 	}
69 	firstsymbol = p -> symbol;
70 	firstbn = bn;
71 	firstextra_flags = p -> extra_flags;
72 	c = v_node->qual;
73 	if ( ( modflag & NOUSE ) && ! lptr( c ) ) {
74 		p -> nl_flags = flagwas;
75 	}
76 	if ( modflag & MOD ) {
77 		p -> nl_flags |= NMOD;
78 	}
79 	/*
80 	 * Only possibilities for p -> class here
81 	 * are the named classes, i.e. CONST, TYPE
82 	 * VAR, PROC, FUNC, REF, or a WITHPTR.
83 	 */
84 	 tr_ptr = &(l_node.list_node);
85 	if ( p -> class == WITHPTR ) {
86 		/*
87 		 * Construct the tree implied by
88 		 * the with statement
89 		 */
90 	    l_node.tag = T_LISTPP;
91 	    tr_ptr->list = &(tr);
92 	    tr_ptr->next = v_node->qual;
93 	    tr.tag = T_FIELD;
94 	    tr.field_node.id_ptr = v_node->cptr;
95 	    c = &(l_node);
96 	}
97 	    /*
98 	     *	this not only puts out the names of functions to call
99 	     *	but also does all the semantic checking of the qualifications.
100 	     */
101 	if ( ! nilfnil( p , c , modflag , firstp , v_node->cptr ) ) {
102 	    return NLNIL;
103 	}
104 	switch (p -> class) {
105 		case WITHPTR:
106 		case REF:
107 			/*
108 			 * Obtain the indirect word
109 			 * of the WITHPTR or REF
110 			 * as the base of our lvalue
111 			 */
112 			putRV( firstsymbol , firstbn , p -> value[ 0 ] ,
113 				firstextra_flags , p2type( p ) );
114 			firstsymbol = 0;
115 			f = 0;		/* have an lv on stack */
116 			o = 0;
117 			break;
118 		case VAR:
119 			if (p->type->class != CRANGE) {
120 				f = 1;		/* no lv on stack yet */
121 				o = p -> value[0];
122 			} else {
123 				error("Conformant array bound %s found where variable required", p->symbol);
124 				return(NIL);
125 			}
126 			break;
127 		default:
128 			error("%s %s found where variable required", classes[p -> class], p -> symbol);
129 			return (NLNIL);
130 	}
131 	/*
132 	 * Loop and handle each
133 	 * qualification on the name
134 	 */
135 	if ( c == NIL &&
136 	    ( modflag & ASGN ) &&
137 	    ( p -> value[ NL_FORV ] & FORVAR ) ) {
138 		error("Can't modify the for variable %s in the range of the loop", p -> symbol);
139 		return (NLNIL);
140 	}
141 	s = 0;
142 	for ( ; c != TR_NIL ; c = c->list_node.next ) {
143 		co = c->list_node.list;
144 		if ( co == TR_NIL ) {
145 			return NLNIL;
146 		}
147 		lastp = p;
148 		p = p -> type;
149 		if ( p == NLNIL ) {
150 			return NLNIL;
151 		}
152 		/*
153 		 * If we haven't seen enough subscripts, and the next
154 		 * qualification isn't array reference, then it's an error.
155 		 */
156 		if (s && co->tag != T_ARY) {
157 			error("Too few subscripts (%d given, %d required)",
158 				s, p->value[0]);
159 		}
160 		switch ( co->tag ) {
161 			case T_PTR:
162 				/*
163 				 * Pointer qualification.
164 				 */
165 				if ( f ) {
166 					putLV( firstsymbol , firstbn , o ,
167 					    firstextra_flags , p2type( p ) );
168 					firstsymbol = 0;
169 				} else {
170 					if (o) {
171 					    putleaf( PCC_ICON , o , 0 , PCCT_INT
172 						    , (char *) 0 );
173 					    putop( PCC_PLUS , PCCTM_PTR | PCCT_CHAR );
174 					}
175 				}
176 				    /*
177 				     * Pointer cannot be
178 				     * nil and file cannot
179 				     * be at end-of-file.
180 				     * the appropriate function name is
181 				     * already out there from nilfnil.
182 				     */
183 				if ( p -> class == PTR ) {
184 					/*
185 					 * this is the indirection from
186 					 * the address of the pointer
187 					 * to the pointer itself.
188 					 * kirk sez:
189 					 * fnil doesn't want this.
190 					 * and does it itself for files
191 					 * since only it knows where the
192 					 * actual window is.
193 					 * but i have to do this for
194 					 * regular pointers.
195 					 */
196 				    putop( PCCOM_UNARY PCC_MUL , p2type( p ) );
197 				    if ( opt( 't' ) ) {
198 					putop( PCC_CALL , PCCT_INT );
199 				    }
200 				} else {
201 				    putop( PCC_CALL , PCCT_INT );
202 				}
203 				f = o = 0;
204 				continue;
205 			case T_ARGL:
206 			case T_ARY:
207 				if ( f ) {
208 					putLV( firstsymbol , firstbn , o ,
209 					    firstextra_flags , p2type( p ) );
210 					firstsymbol = 0;
211 				} else {
212 					if (o) {
213 					    putleaf( PCC_ICON , o , 0 , PCCT_INT
214 						    , (char *) 0 );
215 					    putop( PCC_PLUS , PCCT_INT );
216 					}
217 				}
218 				s = arycod( p , co->ary_node.expr_list, s);
219 				if (s == p->value[0]) {
220 					s = 0;
221 				} else {
222 					p = lastp;
223 				}
224 				f = o = 0;
225 				continue;
226 			case T_FIELD:
227 				/*
228 				 * Field names are just
229 				 * an offset with some
230 				 * semantic checking.
231 				 */
232 				p = reclook(p, co->field_node.id_ptr);
233 				o += p -> value[0];
234 				continue;
235 			default:
236 				panic("lval2");
237 		}
238 	}
239 	if (s) {
240 		error("Too few subscripts (%d given, %d required)",
241 			s, p->type->value[0]);
242 		return NLNIL;
243 	}
244 	if (f) {
245 		if ( required == LREQ ) {
246 		    putLV( firstsymbol , firstbn , o ,
247 			    firstextra_flags , p2type( p -> type ) );
248 		} else {
249 		    putRV( firstsymbol , firstbn , o ,
250 			    firstextra_flags , p2type( p -> type ) );
251 		}
252 	} else {
253 		if (o) {
254 		    putleaf( PCC_ICON , o , 0 , PCCT_INT , (char *) 0 );
255 		    putop( PCC_PLUS , PCCT_INT );
256 		}
257 		if ( required == RREQ ) {
258 		    putop( PCCOM_UNARY PCC_MUL , p2type( p -> type ) );
259 		}
260 	}
261 	return ( p -> type );
262 }
263 
264     /*
265      *	this recursively follows done a list of qualifications
266      *	and puts out the beginnings of calls to fnil for files
267      *	or nil for pointers (if checking is on) on the way back.
268      *	this returns true or false.
269      */
270 bool
271 nilfnil( p , c , modflag , firstp , r2 )
272     struct nl	 *p;
273     struct tnode *c;
274     int		modflag;
275     struct nl	*firstp;
276     char	*r2;		/* no, not r2-d2 */
277     {
278 	struct tnode 	*co;
279 	struct nl	*lastp;
280 	int		t;
281 	static int	s = 0;
282 
283 	if ( c == TR_NIL ) {
284 	    return TRUE;
285 	}
286 	co = ( c->list_node.list );
287 	if ( co == TR_NIL ) {
288 		return FALSE;
289 	}
290 	lastp = p;
291 	p = p -> type;
292 	if ( p == NLNIL ) {
293 		return FALSE;
294 	}
295 	switch ( co->tag ) {
296 	    case T_PTR:
297 		    /*
298 		     * Pointer qualification.
299 		     */
300 		    lastp -> nl_flags |= NUSED;
301 		    if ( p -> class != PTR && p -> class != FILET) {
302 			    error("^ allowed only on files and pointers, not on %ss", nameof(p));
303 			    goto bad;
304 		    }
305 		    break;
306 	    case T_ARGL:
307 		    if ( p -> class != ARRAY ) {
308 			    if ( lastp == firstp ) {
309 				    error("%s is a %s, not a function", r2, classes[firstp -> class]);
310 			    } else {
311 				    error("Illegal function qualificiation");
312 			    }
313 			    return FALSE;
314 		    }
315 		    recovered();
316 		    error("Pascal uses [] for subscripting, not ()");
317 		    /* and fall through */
318 	    case T_ARY:
319 		    if ( p -> class != ARRAY ) {
320 			    error("Subscripting allowed only on arrays, not on %ss", nameof(p));
321 			    goto bad;
322 		    }
323 		    codeoff();
324 		    s = arycod( p , co->ary_node.expr_list , s );
325 		    codeon();
326 		    switch ( s ) {
327 			    case 0:
328 				    return FALSE;
329 			    case -1:
330 				    goto bad;
331 		    }
332 		    if (s == p->value[0]) {
333 			    s = 0;
334 		    } else {
335 			    p = lastp;
336 		    }
337 		    break;
338 	    case T_FIELD:
339 		    /*
340 		     * Field names are just
341 		     * an offset with some
342 		     * semantic checking.
343 		     */
344 		    if ( p -> class != RECORD ) {
345 			    error(". allowed only on records, not on %ss", nameof(p));
346 			    goto bad;
347 		    }
348 		    if ( co->field_node.id_ptr == NIL ) {
349 			    return FALSE;
350 		    }
351 		    p = reclook( p , co->field_node.id_ptr );
352 		    if ( p == NIL ) {
353 			    error("%s is not a field in this record", co->field_node.id_ptr);
354 			    goto bad;
355 		    }
356 		    if ( modflag & MOD ) {
357 			    p -> nl_flags |= NMOD;
358 		    }
359 		    if ((modflag & NOUSE) == 0 || lptr(c->field_node.other )) {
360 			    p -> nl_flags |= NUSED;
361 		    }
362 		    break;
363 	    default:
364 		    panic("nilfnil");
365 	}
366 	    /*
367 	     *	recursive call, check the rest of the qualifications.
368 	     */
369 	if ( ! nilfnil( p , c->list_node.next , modflag , firstp , r2 ) ) {
370 	    return FALSE;
371 	}
372 	    /*
373 	     *	the point of all this.
374 	     */
375 	if ( co->tag == T_PTR ) {
376 	    if ( p -> class == PTR ) {
377 		    if ( opt( 't' ) ) {
378 			putleaf( PCC_ICON , 0 , 0
379 			    , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
380 			    , "_NIL" );
381 		    }
382 	    } else {
383 		    putleaf( PCC_ICON , 0 , 0
384 			, PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR )
385 			, "_FNIL" );
386 	    }
387 	}
388 	return TRUE;
389 bad:
390 	cerror("Error occurred on qualification of %s", r2);
391 	return FALSE;
392     }
393 #endif PC
394