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