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