BSD 4_3 release
[unix-history] / usr / src / ucb / pascal / src / rec.c
CommitLineData
252367af
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
9f7cd8aa 6
72fbef68 7#ifndef lint
95f51977 8static char sccsid[] = "@(#)rec.c 5.1 (Berkeley) 6/5/85";
252367af 9#endif not lint
9f7cd8aa
PK
10
11#include "whoami.h"
12#include "0.h"
13#include "tree.h"
14#include "opcode.h"
d25ca1ea 15#include "align.h"
72fbef68 16#include "tree_ty.h"
d25ca1ea
PK
17
18 /*
19 * set this to TRUE with adb to turn on record alignment/offset debugging.
20 */
21bool debug_records = FALSE;
22#define DEBUG_RECORDS(x) if (debug_records) { x ; } else
9f7cd8aa
PK
23
24/*
25 * Build a record namelist entry.
26 * Some of the processing here is somewhat involved.
27 * The basic structure we are building is as follows.
28 *
d25ca1ea
PK
29 * Each record has a main RECORD entry,
30 * with an attached chain of fields as ->chain;
72fbef68 31 * these enclude all the fields in all the variants of this record.
d25ca1ea
PK
32 * Fields are cons'ed to the front of the ->chain list as they are discovered.
33 * This is for reclook(), but not for sizing and aligning offsets.
9f7cd8aa 34 *
d25ca1ea
PK
35 * If there are variants to the record, NL_TAG points to the field which
36 * is the tag. If its name is NIL, the tag field is unnamed, and is not
37 * allocated any space in the record.
9f7cd8aa
PK
38 * Attached to NL_VARNT is a chain of VARNT structures
39 * describing each of the variants. These are further linked
40 * through ->chain. Each VARNT has, in ->range[0] the value of
41 * the associated constant, and each points at a RECORD describing
42 * the subrecord through NL_VTOREC. These pointers are not unique,
43 * more than one VARNT may reference the same RECORD.
44 *
d25ca1ea
PK
45 * On the first pass, we traverse the parse tree and construct the namelist
46 * entries. This pass fills in the alignment of each record (including
47 * subrecords (the alignment of a record is the maximum of the alignments
48 * of any of its fields).
49 * A second pass over the namelist entries fills in the offsets of each field
50 * based on the alignments required. This second pass uses the NL_FIELDLIST
51 * chaining of fields, and the NL_TAG pointer and the NL_VARNT pointer to get
52 * to fields in the order in which they were declared.
53 * This second pass can not be folded into the first pass,
54 * as the starting offset of all variants is the same,
55 * so we must see all the variants (and especially must know their alignments)
56 * before assigning offsets. With the alignments calculated (by the first
57 * pass) this can be done in one top down pass, max'ing over the alignment of
58 * variants before assigning offsets to any of them.
9f7cd8aa
PK
59 */
60
61/*
62 * P0 points to the outermost RECORD for name searches.
63 */
64struct nl *P0;
65
d25ca1ea 66struct nl *
9f7cd8aa 67tyrec(r, off)
72fbef68
RT
68 struct tnode *r;
69 int off;
9f7cd8aa 70{
d25ca1ea 71 struct nl *recp;
9f7cd8aa 72
d25ca1ea
PK
73 DEBUG_RECORDS(fprintf(stderr,"[tyrec] off=%d\n", off));
74 /*
75 * build namelist structure for the outermost record type.
76 * then calculate offsets (starting at 0) of the fields
77 * in this record and its variant subrecords.
78 */
79 recp = tyrec1(r, TRUE);
72fbef68 80 rec_offsets(recp, (long) 0);
d25ca1ea 81 return recp;
9f7cd8aa
PK
82}
83
84/*
85 * Define a record namelist entry.
d25ca1ea
PK
86 * r is the tree for the record to be built.
87 * first is a boolean indicating whether this is an outermost record,
88 * for name lookups.
89 * p is the record we define here.
90 * P0was is a local which stacks the enclosing value of P0 in the stack frame,
91 * since tyrec1() is recursive.
9f7cd8aa
PK
92 */
93struct nl *
d25ca1ea 94tyrec1(r, first)
72fbef68 95 register struct tnode *r; /* T_FLDLST */
d25ca1ea 96 bool first;
9f7cd8aa
PK
97{
98 register struct nl *p, *P0was;
99
d25ca1ea 100 DEBUG_RECORDS(fprintf(stderr,"[tyrec1] first=%d\n", first));
72fbef68 101 p = defnl((char *) 0, RECORD, NLNIL, 0);
9f7cd8aa
PK
102 P0was = P0;
103 if (first)
104 P0 = p;
105#ifndef PI0
d25ca1ea 106 p->align_info = A_MIN;
9f7cd8aa 107#endif
72fbef68
RT
108 if (r != TR_NIL) {
109 fields(p, r->fldlst.fix_list);
110 variants(p, r->fldlst.variant);
9f7cd8aa 111 }
9f7cd8aa
PK
112 P0 = P0was;
113 return (p);
114}
115
116/*
117 * Define the fixed part fields for p.
d25ca1ea
PK
118 * hang them, in order, from the record entry, through ->ptr[NL_FIELDLIST].
119 * the fieldlist is a tconc structure, and is manipulated
120 * just like newlist(), addlist(), fixlist() in the parser.
9f7cd8aa 121 */
9f7cd8aa
PK
122fields(p, r)
123 struct nl *p;
72fbef68 124 struct tnode *r; /* T_LISTPP */
9f7cd8aa 125{
72fbef68 126 register struct tnode *fp, *tp, *ip;
d25ca1ea
PK
127 struct nl *jp;
128 struct nl *fieldnlp;
9f7cd8aa 129
d25ca1ea 130 DEBUG_RECORDS(fprintf(stderr,"[fields]\n"));
72fbef68
RT
131 for (fp = r; fp != TR_NIL; fp = fp->list_node.next) {
132 tp = fp->list_node.list;
133 if (tp == TR_NIL)
9f7cd8aa 134 continue;
72fbef68
RT
135 jp = gtype(tp->rfield.type);
136 line = tp->rfield.line_no;
137 for (ip = tp->rfield.id_list; ip != TR_NIL;
138 ip = ip->list_node.next) {
139 fieldnlp = deffld(p, (char *) ip->list_node.list, jp);
d25ca1ea
PK
140 if ( p->ptr[NL_FIELDLIST] == NIL ) {
141 /* newlist */
142 p->ptr[NL_FIELDLIST] = fieldnlp;
143 fieldnlp->ptr[NL_FIELDLIST] = fieldnlp;
144 } else {
145 /* addlist */
146 fieldnlp->ptr[NL_FIELDLIST] =
147 p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST];
148 p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = fieldnlp;
149 p->ptr[NL_FIELDLIST] = fieldnlp;
150 }
151 }
152 }
153 if ( p->ptr[NL_FIELDLIST] != NIL ) {
154 /* fixlist */
155 fieldnlp = p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST];
156 p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = NIL;
157 p->ptr[NL_FIELDLIST] = fieldnlp;
9f7cd8aa
PK
158 }
159}
160
161/*
162 * Define the variants for RECORD p.
163 */
9f7cd8aa
PK
164variants(p, r)
165 struct nl *p;
72fbef68 166 register struct tnode *r; /* T_TYVARPT */
9f7cd8aa 167{
72fbef68
RT
168 register struct tnode *vc, *v;
169 struct nl *vr;
9f7cd8aa
PK
170 struct nl *ct;
171
d25ca1ea 172 DEBUG_RECORDS(fprintf(stderr,"[variants]\n"));
72fbef68 173 if (r == TR_NIL)
9f7cd8aa 174 return;
72fbef68
RT
175 ct = gtype(r->varpt.type_id);
176 if ( ( ct != NLNIL ) && ( isnta( ct , "bcsi" ) ) ) {
9f7cd8aa
PK
177 error("Tag fields cannot be %ss" , nameof( ct ) );
178 }
72fbef68 179 line = r->varpt.line_no;
9f7cd8aa
PK
180 /*
181 * Want it even if r[2] is NIL so
182 * we check its type in "new" and "dispose"
183 * calls -- link it to NL_TAG.
184 */
72fbef68
RT
185 p->ptr[NL_TAG] = deffld(p, r->varpt.cptr, ct);
186 for (vc = r->varpt.var_list; vc != TR_NIL; vc = vc->list_node.next) {
187 v = vc->list_node.list;
188 if (v == TR_NIL)
9f7cd8aa 189 continue;
72fbef68 190 vr = tyrec1(v->tyvarnt.fld_list, FALSE);
9f7cd8aa 191#ifndef PI0
d25ca1ea
PK
192 DEBUG_RECORDS(
193 fprintf(stderr,
194 "[variants] p->align_info %d vr->align_info %d\n",
195 p->align_info, vr->align_info));
196 if (vr->align_info > p->align_info) {
197 p->align_info = vr->align_info;
198 }
9f7cd8aa 199#endif
72fbef68
RT
200 line = v->tyvarnt.line_no;
201 for (v = v->tyvarnt.const_list; v != TR_NIL;
202 v = v->list_node.next)
203 (void) defvnt(p, v->list_node.list, vr, ct);
9f7cd8aa
PK
204 }
205}
206
207/*
208 * Define a field in subrecord p of record P0
209 * with name s and type t.
210 */
211struct nl *
212deffld(p, s, t)
213 struct nl *p;
214 register char *s;
215 register struct nl *t;
216{
217 register struct nl *fp;
218
d25ca1ea 219 DEBUG_RECORDS(fprintf(stderr,"[deffld] s=<%s>\n", s));
9f7cd8aa
PK
220 if (reclook(P0, s) != NIL) {
221#ifndef PI1
222 error("%s is a duplicate field name in this record", s);
223#endif
224 s = NIL;
225 }
9f7cd8aa 226 /*
d25ca1ea 227 * enter the field with its type
9f7cd8aa 228 */
9f7cd8aa 229 fp = enter(defnl(s, FIELD, t, 0));
d25ca1ea
PK
230 /*
231 * if no name, then this is an unnamed tag,
232 * so don't link it into reclook()'s chain.
233 */
9f7cd8aa
PK
234 if (s != NIL) {
235 fp->chain = P0->chain;
236 P0->chain = fp;
237#ifndef PI0
238 /*
d25ca1ea 239 * and the alignment is propagated back.
9f7cd8aa 240 */
d25ca1ea
PK
241 fp->align_info = align(t);
242 DEBUG_RECORDS(
243 fprintf(stderr,
244 "[deffld] fp->align_info %d p->align_info %d \n",
245 fp->align_info, p->align_info));
246 if (fp->align_info > p->align_info) {
247 p->align_info = fp->align_info;
248 }
9f7cd8aa
PK
249#endif
250 if (t != NIL) {
251 P0->nl_flags |= t->nl_flags & NFILES;
252 p->nl_flags |= t->nl_flags & NFILES;
253 }
9f7cd8aa
PK
254 }
255 return (fp);
256}
257
258/*
259 * Define a variant from the constant tree of t
260 * in subrecord p of record P0 where the casetype
261 * is ct and the variant record to be associated is vr.
262 */
263struct nl *
264defvnt(p, t, vr, ct)
265 struct nl *p, *vr;
72fbef68 266 struct tnode *t; /* CHAR_CONST or SIGN_CONST */
9f7cd8aa
PK
267 register struct nl *ct;
268{
269 register struct nl *av;
270
271 gconst(t);
272 if (ct != NIL && incompat(con.ctype, ct , t )) {
273#ifndef PI1
274 cerror("Variant label type incompatible with selector type");
275#endif
276 ct = NIL;
277 }
72fbef68 278 av = defnl((char *) 0, VARNT, ct, 0);
9f7cd8aa
PK
279#ifndef PI1
280 if (ct != NIL)
281 uniqv(p);
d25ca1ea 282#endif not PI1
9f7cd8aa
PK
283 av->chain = p->ptr[NL_VARNT];
284 p->ptr[NL_VARNT] = av;
285 av->ptr[NL_VTOREC] = vr;
286 av->range[0] = con.crval;
287 return (av);
288}
289
290#ifndef PI1
291/*
292 * Check that the constant label value
293 * is unique among the labels in this variant.
294 */
295uniqv(p)
296 struct nl *p;
297{
298 register struct nl *vt;
299
300 for (vt = p->ptr[NL_VARNT]; vt != NIL; vt = vt->chain)
301 if (vt->range[0] == con.crval) {
302 error("Duplicate variant case label in record");
303 return;
304 }
305}
306#endif
307
308/*
309 * See if the field name s is defined
310 * in the record p, returning a pointer
311 * to it namelist entry if it is.
312 */
313struct nl *
314reclook(p, s)
315 register struct nl *p;
316 char *s;
317{
318
319 if (p == NIL || s == NIL)
320 return (NIL);
321 for (p = p->chain; p != NIL; p = p->chain)
322 if (p->symbol == s)
323 return (p);
324 return (NIL);
325}
d25ca1ea
PK
326
327 /*
328 * descend namelist entry for a record and assign offsets.
329 * fields go at the next higher offset that suits their alignment.
330 * all variants of a record start at the same offset, which is suitable
331 * for the alignment of their worst aligned field. thus the size of a
332 * record is independent of whether or not it is a variant
333 * (a desirable property).
334 * records come to us in the namelist, where they have been annotated
335 * with the maximum alignment their fields require.
336 * the starting offset is passed to us, and is passed recursively for
337 * variant records within records.
338 * the final maximum size of each record is recorded in the namelist
339 * in the value[NL_OFFS] field of the namelist for the record.
340 *
341 * this is supposed to match the offsets used by the c compiler
342 * so people can share records between modules in both languages.
343 */
344rec_offsets(recp, offset)
345 struct nl *recp; /* pointer to the namelist record */
346 long offset; /* starting offset for this record/field */
347{
348 long origin; /* offset of next field */
349 struct nl *fieldnlp; /* the current field */
350 struct nl *varntnlp; /* the current variant */
351 struct nl *vrecnlp; /* record for the current variant */
d25ca1ea
PK
352
353 if ( recp == NIL ) {
354 return;
355 }
72fbef68 356 origin = roundup((int) offset,(long) recp->align_info);
d25ca1ea
PK
357 if (origin != offset) {
358 fprintf(stderr,
359 "[rec_offsets] offset=%d recp->align_info=%d origin=%d\n",
360 offset, recp->align_info, origin);
361 panic("rec_offsets");
362 }
363 DEBUG_RECORDS(
364 fprintf(stderr,
365 "[rec_offsets] offset %d recp->align %d origin %d\n",
366 offset, recp->align_info, origin));
367 /*
368 * fixed fields are forward linked though ->ptr[NL_FIELDLIST]
369 * give them all suitable offsets.
370 */
371 for ( fieldnlp = recp->ptr[NL_FIELDLIST];
372 fieldnlp != NIL;
373 fieldnlp = fieldnlp->ptr[NL_FIELDLIST] ) {
72fbef68 374 origin = roundup((int) origin,(long) align(fieldnlp->type));
d25ca1ea
PK
375 fieldnlp->value[NL_OFFS] = origin;
376 DEBUG_RECORDS(
377 fprintf(stderr,"[rec_offsets] symbol %s origin %d\n",
378 fieldnlp->symbol, origin));
379 origin += lwidth(fieldnlp->type);
380 }
381 /*
382 * this is the extent of the record, so far
383 */
384 recp->value[NL_OFFS] = origin;
385 /*
386 * if we have a tag field, we have variants to deal with
387 */
388 if ( recp->ptr[NL_TAG] ) {
389 /*
390 * if tag field is unnamed, then don't allocate space for it.
391 */
392 fieldnlp = recp->ptr[NL_TAG];
393 if ( fieldnlp->symbol != NIL ) {
72fbef68 394 origin = roundup((int) origin,(long) align(fieldnlp->type));
d25ca1ea
PK
395 fieldnlp->value[NL_OFFS] = origin;
396 DEBUG_RECORDS(fprintf(stderr,"[rec_offsets] tag %s origin\n",
397 fieldnlp->symbol, origin));
398 origin += lwidth(fieldnlp->type);
399 }
400 /*
401 * find maximum alignment of records of variants
402 */
403 for ( varntnlp = recp->ptr[NL_VARNT];
404 varntnlp != NIL;
405 varntnlp = varntnlp -> chain ) {
406 vrecnlp = varntnlp->ptr[NL_VTOREC];
407 DEBUG_RECORDS(
408 fprintf(stderr,
409 "[rec_offsets] maxing variant %d align_info %d\n",
410 varntnlp->value[0], vrecnlp->align_info));
72fbef68 411 origin = roundup((int) origin,(long) vrecnlp->align_info);
d25ca1ea
PK
412 }
413 DEBUG_RECORDS(
414 fprintf(stderr, "[rec_offsets] origin of variants %d\n", origin));
415 /*
416 * assign offsets to fields of records of the variants
417 * keep maximum length of the current record.
418 */
419 for ( varntnlp = recp->ptr[NL_VARNT];
420 varntnlp != NIL;
421 varntnlp = varntnlp -> chain ) {
422 vrecnlp = varntnlp->ptr[NL_VTOREC];
423 /*
424 * assign offsets to fields of the variant.
425 * recursive call on rec_offsets.
426 */
427 rec_offsets(vrecnlp,origin);
428 /*
429 * extent of the record is the
430 * maximum extent of all variants
431 */
432 if ( vrecnlp->value[NL_OFFS] > recp->value[NL_OFFS] ) {
433 recp->value[NL_OFFS] = vrecnlp->value[NL_OFFS];
434 }
435 }
436 }
437 /*
438 * roundup the size of the record to its alignment
439 */
440 DEBUG_RECORDS(
441 fprintf(stderr,
442 "[rec_offsets] recp->value[NL_OFFS] %d ->align_info %d\n",
443 recp->value[NL_OFFS], recp->align_info));
72fbef68 444 recp->value[NL_OFFS] = roundup(recp->value[NL_OFFS],(long) recp->align_info);
d25ca1ea 445}