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