xref: /csrg-svn/usr.bin/pascal/src/rec.c (revision 8681)
1770Speter /* Copyright (c) 1979 Regents of the University of California */
2770Speter 
3*8681Speter static char sccsid[] = "@(#)rec.c 1.5 10/19/82";
4770Speter 
5770Speter #include "whoami.h"
6770Speter #include "0.h"
7770Speter #include "tree.h"
8770Speter #include "opcode.h"
9*8681Speter #include "align.h"
10770Speter 
11*8681Speter     /*
12*8681Speter      *	set this to TRUE with adb to turn on record alignment/offset debugging.
13*8681Speter      */
14*8681Speter bool	debug_records = FALSE;
15*8681Speter #define	DEBUG_RECORDS(x)	if (debug_records) { x ; } else
16*8681Speter 
17770Speter /*
18770Speter  * Build a record namelist entry.
19770Speter  * Some of the processing here is somewhat involved.
20770Speter  * The basic structure we are building is as follows.
21770Speter  *
22*8681Speter  * Each record has a main RECORD entry,
23*8681Speter  * with an attached chain of fields as ->chain;
24*8681Speter  * these include all the fields in all the variants of this record.
25*8681Speter  * Fields are cons'ed to the front of the ->chain list as they are discovered.
26*8681Speter  * This is for reclook(), but not for sizing and aligning offsets.
27770Speter  *
28*8681Speter  * If there are variants to the record, NL_TAG points to the field which
29*8681Speter  * is the tag.  If its name is NIL, the tag field is unnamed, and is not
30*8681Speter  * allocated any space in the record.
31770Speter  * Attached to NL_VARNT is a chain of VARNT structures
32770Speter  * describing each of the variants.  These are further linked
33770Speter  * through ->chain.  Each VARNT has, in ->range[0] the value of
34770Speter  * the associated constant, and each points at a RECORD describing
35770Speter  * the subrecord through NL_VTOREC.  These pointers are not unique,
36770Speter  * more than one VARNT may reference the same RECORD.
37770Speter  *
38*8681Speter  * On the first pass, we traverse the parse tree and construct the namelist
39*8681Speter  * entries.  This pass fills in the alignment of each record (including
40*8681Speter  * subrecords (the alignment of a record is the maximum of the alignments
41*8681Speter  * of any of its fields).
42*8681Speter  * A second pass over the namelist entries fills in the offsets of each field
43*8681Speter  * based on the alignments required.  This second pass uses the NL_FIELDLIST
44*8681Speter  * chaining of fields, and the NL_TAG pointer and the NL_VARNT pointer to get
45*8681Speter  * to fields in the order in which they were declared.
46*8681Speter  * This second pass can not be folded into the first pass,
47*8681Speter  * as the starting offset of all variants is the same,
48*8681Speter  * so we must see all the variants (and especially must know their alignments)
49*8681Speter  * before assigning offsets.  With the alignments calculated (by the first
50*8681Speter  * pass) this can be done in one top down pass, max'ing over the alignment of
51*8681Speter  * variants before assigning offsets to any of them.
52770Speter  */
53770Speter 
54770Speter /*
55770Speter  * P0 points to the outermost RECORD for name searches.
56770Speter  */
57770Speter struct	nl *P0;
58770Speter 
59*8681Speter struct nl *
60770Speter tyrec(r, off)
61770Speter 	int *r, off;
62770Speter {
63*8681Speter 	struct nl	*recp;
64770Speter 
65*8681Speter 	DEBUG_RECORDS(fprintf(stderr,"[tyrec] off=%d\n", off));
66*8681Speter 	    /*
67*8681Speter 	     *	build namelist structure for the outermost record type.
68*8681Speter 	     *	then calculate offsets (starting at 0) of the fields
69*8681Speter 	     *	in this record and its variant subrecords.
70*8681Speter 	     */
71*8681Speter 	recp = tyrec1(r, TRUE);
72*8681Speter 	rec_offsets(recp, 0);
73*8681Speter 	return recp;
74770Speter }
75770Speter 
76770Speter /*
77770Speter  * Define a record namelist entry.
78*8681Speter  * r is the tree for the record to be built.
79*8681Speter  * first is a boolean indicating whether this is an outermost record,
80*8681Speter  * for name lookups.
81*8681Speter  * p is the record we define here.
82*8681Speter  * P0was is a local which stacks the enclosing value of P0 in the stack frame,
83*8681Speter  * since tyrec1() is recursive.
84770Speter  */
85770Speter struct nl *
86*8681Speter tyrec1(r, first)
87770Speter 	register int *r;
88*8681Speter 	bool first;
89770Speter {
90770Speter 	register struct nl *p, *P0was;
91770Speter 
92*8681Speter 	DEBUG_RECORDS(fprintf(stderr,"[tyrec1] first=%d\n", first));
93770Speter 	p = defnl(0, RECORD, 0, 0);
94770Speter 	P0was = P0;
95770Speter 	if (first)
96770Speter 		P0 = p;
97770Speter #ifndef PI0
98*8681Speter 	p->align_info = A_MIN;
99770Speter #endif
100770Speter 	if (r != NIL) {
101770Speter 		fields(p, r[2]);
102770Speter 		variants(p, r[3]);
103770Speter 	}
104770Speter 	P0 = P0was;
105770Speter 	return (p);
106770Speter }
107770Speter 
108770Speter /*
109770Speter  * Define the fixed part fields for p.
110*8681Speter  * hang them, in order, from the record entry, through ->ptr[NL_FIELDLIST].
111*8681Speter  * the fieldlist is a tconc structure, and is manipulated
112*8681Speter  * just like newlist(), addlist(), fixlist() in the parser.
113770Speter  */
114770Speter fields(p, r)
115770Speter 	struct nl *p;
116770Speter 	int *r;
117770Speter {
118*8681Speter 	register int	*fp, *tp, *ip;
119*8681Speter 	struct nl	*jp;
120*8681Speter 	struct nl	*fieldnlp;
121770Speter 
122*8681Speter 	DEBUG_RECORDS(fprintf(stderr,"[fields]\n"));
123770Speter 	for (fp = r; fp != NIL; fp = fp[2]) {
124770Speter 		tp = fp[1];
125770Speter 		if (tp == NIL)
126770Speter 			continue;
127770Speter 		jp = gtype(tp[3]);
128770Speter 		line = tp[1];
129*8681Speter 		for (ip = tp[2]; ip != NIL; ip = ip[2]) {
130*8681Speter 		    fieldnlp = deffld(p, ip[1], jp);
131*8681Speter 		    if ( p->ptr[NL_FIELDLIST] == NIL ) {
132*8681Speter 			    /* newlist */
133*8681Speter 			p->ptr[NL_FIELDLIST] = fieldnlp;
134*8681Speter 			fieldnlp->ptr[NL_FIELDLIST] = fieldnlp;
135*8681Speter 		    } else {
136*8681Speter 			    /* addlist */
137*8681Speter 			fieldnlp->ptr[NL_FIELDLIST] =
138*8681Speter 				p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST];
139*8681Speter 			p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = fieldnlp;
140*8681Speter 			p->ptr[NL_FIELDLIST] = fieldnlp;
141*8681Speter 		    }
142*8681Speter 		}
143770Speter 	}
144*8681Speter 	if ( p->ptr[NL_FIELDLIST] != NIL ) {
145*8681Speter 		/* fixlist */
146*8681Speter 	    fieldnlp = p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST];
147*8681Speter 	    p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = NIL;
148*8681Speter 	    p->ptr[NL_FIELDLIST] = fieldnlp;
149*8681Speter 	}
150770Speter }
151770Speter 
152770Speter /*
153770Speter  * Define the variants for RECORD p.
154770Speter  */
155770Speter variants(p, r)
156770Speter 	struct nl *p;
157770Speter 	register int *r;
158770Speter {
159770Speter 	register int *vc, *v;
160770Speter 	int *vr;
161770Speter 	struct nl *ct;
162770Speter 
163*8681Speter 	DEBUG_RECORDS(fprintf(stderr,"[variants]\n"));
164770Speter 	if (r == NIL)
165770Speter 		return;
166770Speter 	ct = gtype(r[3]);
1673405Speter 	if ( ( ct != NIL ) && ( isnta( ct , "bcsi" ) ) ) {
168770Speter 	    error("Tag fields cannot be %ss" , nameof( ct ) );
169770Speter 	}
170770Speter 	line = r[1];
171770Speter 	/*
172770Speter 	 * Want it even if r[2] is NIL so
173770Speter 	 * we check its type in "new" and "dispose"
174770Speter 	 * calls -- link it to NL_TAG.
175770Speter 	 */
176770Speter 	p->ptr[NL_TAG] = deffld(p, r[2], ct);
177770Speter 	for (vc = r[4]; vc != NIL; vc = vc[2]) {
178770Speter 		v = vc[1];
179770Speter 		if (v == NIL)
180770Speter 			continue;
181*8681Speter 		vr = tyrec1(v[3], FALSE);
182770Speter #ifndef PI0
183*8681Speter 		DEBUG_RECORDS(
184*8681Speter 		    fprintf(stderr,
185*8681Speter 			"[variants] p->align_info %d vr->align_info %d\n",
186*8681Speter 			p->align_info, vr->align_info));
187*8681Speter 		if (vr->align_info > p->align_info) {
188*8681Speter 		    p->align_info = vr->align_info;
189*8681Speter 		}
190770Speter #endif
191770Speter 		line = v[1];
192770Speter 		for (v = v[2]; v != NIL; v = v[2])
193770Speter 			defvnt(p, v[1], vr, ct);
194770Speter 	}
195770Speter }
196770Speter 
197770Speter /*
198770Speter  * Define a field in subrecord p of record P0
199770Speter  * with name s and type t.
200770Speter  */
201770Speter struct nl *
202770Speter deffld(p, s, t)
203770Speter 	struct nl *p;
204770Speter 	register char *s;
205770Speter 	register struct nl *t;
206770Speter {
207770Speter 	register struct nl *fp;
208770Speter 
209*8681Speter 	DEBUG_RECORDS(fprintf(stderr,"[deffld] s=<%s>\n", s));
210770Speter 	if (reclook(P0, s) != NIL) {
211770Speter #ifndef PI1
212770Speter 		error("%s is a duplicate field name in this record", s);
213770Speter #endif
214770Speter 		s = NIL;
215770Speter 	}
216770Speter 	    /*
217*8681Speter 	     *	enter the field with its type
218770Speter 	     */
219770Speter 	fp = enter(defnl(s, FIELD, t, 0));
220*8681Speter 	    /*
221*8681Speter 	     *	if no name, then this is an unnamed tag,
222*8681Speter 	     *	so don't link it into reclook()'s chain.
223*8681Speter 	     */
224770Speter 	if (s != NIL) {
225770Speter 		fp->chain = P0->chain;
226770Speter 		P0->chain = fp;
227770Speter #ifndef PI0
228770Speter 		    /*
229*8681Speter 		     * and the alignment is propagated back.
230770Speter 		     */
231*8681Speter 		fp->align_info = align(t);
232*8681Speter 		DEBUG_RECORDS(
233*8681Speter 		    fprintf(stderr,
234*8681Speter 			"[deffld] fp->align_info %d p->align_info %d \n",
235*8681Speter 			fp->align_info, p->align_info));
236*8681Speter 		if (fp->align_info > p->align_info) {
237*8681Speter 		    p->align_info = fp->align_info;
238*8681Speter 		}
239770Speter #endif
240770Speter 		if (t != NIL) {
241770Speter 			P0->nl_flags |= t->nl_flags & NFILES;
242770Speter 			p->nl_flags |= t->nl_flags & NFILES;
243770Speter 		}
244770Speter 	}
245770Speter 	return (fp);
246770Speter }
247770Speter 
248770Speter /*
249770Speter  * Define a variant from the constant tree of t
250770Speter  * in subrecord p of record P0 where the casetype
251770Speter  * is ct and the variant record to be associated is vr.
252770Speter  */
253770Speter struct nl *
254770Speter defvnt(p, t, vr, ct)
255770Speter 	struct nl *p, *vr;
256770Speter 	int *t;
257770Speter 	register struct nl *ct;
258770Speter {
259770Speter 	register struct nl *av;
260770Speter 
261770Speter 	gconst(t);
262770Speter 	if (ct != NIL && incompat(con.ctype, ct , t )) {
263770Speter #ifndef PI1
264770Speter 		cerror("Variant label type incompatible with selector type");
265770Speter #endif
266770Speter 		ct = NIL;
267770Speter 	}
268770Speter 	av = defnl(0, VARNT, ct, 0);
269770Speter #ifndef PI1
270770Speter 	if (ct != NIL)
271770Speter 		uniqv(p);
272*8681Speter #endif not PI1
273770Speter 	av->chain = p->ptr[NL_VARNT];
274770Speter 	p->ptr[NL_VARNT] = av;
275770Speter 	av->ptr[NL_VTOREC] = vr;
276770Speter 	av->range[0] = con.crval;
277770Speter 	return (av);
278770Speter }
279770Speter 
280770Speter #ifndef PI1
281770Speter /*
282770Speter  * Check that the constant label value
283770Speter  * is unique among the labels in this variant.
284770Speter  */
285770Speter uniqv(p)
286770Speter 	struct nl *p;
287770Speter {
288770Speter 	register struct nl *vt;
289770Speter 
290770Speter 	for (vt = p->ptr[NL_VARNT]; vt != NIL; vt = vt->chain)
291770Speter 		if (vt->range[0] == con.crval) {
292770Speter 			error("Duplicate variant case label in record");
293770Speter 			return;
294770Speter 		}
295770Speter }
296770Speter #endif
297770Speter 
298770Speter /*
299770Speter  * See if the field name s is defined
300770Speter  * in the record p, returning a pointer
301770Speter  * to it namelist entry if it is.
302770Speter  */
303770Speter struct nl *
304770Speter reclook(p, s)
305770Speter 	register struct nl *p;
306770Speter 	char *s;
307770Speter {
308770Speter 
309770Speter 	if (p == NIL || s == NIL)
310770Speter 		return (NIL);
311770Speter 	for (p = p->chain; p != NIL; p = p->chain)
312770Speter 		if (p->symbol == s)
313770Speter 			return (p);
314770Speter 	return (NIL);
315770Speter }
316*8681Speter 
317*8681Speter     /*
318*8681Speter      *	descend namelist entry for a record and assign offsets.
319*8681Speter      *	fields go at the next higher offset that suits their alignment.
320*8681Speter      *	all variants of a record start at the same offset, which is suitable
321*8681Speter      *	for the alignment of their worst aligned field.  thus the size of a
322*8681Speter      *	record is independent of whether or not it is a variant
323*8681Speter      *	(a desirable property).
324*8681Speter      *	records come to us in the namelist, where they have been annotated
325*8681Speter      *	with the maximum alignment their fields require.
326*8681Speter      *	the starting offset is passed to us, and is passed recursively for
327*8681Speter      *	variant records within records.
328*8681Speter      *	the final maximum size of each record is recorded in the namelist
329*8681Speter      *	in the value[NL_OFFS] field of the namelist for the record.
330*8681Speter      *
331*8681Speter      *	this is supposed to match the offsets used by the c compiler
332*8681Speter      *	so people can share records between modules in both languages.
333*8681Speter      */
334*8681Speter rec_offsets(recp, offset)
335*8681Speter     struct nl	*recp;		/* pointer to the namelist record */
336*8681Speter     long	offset;		/* starting offset for this record/field */
337*8681Speter {
338*8681Speter     long	origin;		/* offset of next field */
339*8681Speter     struct nl	*fieldnlp;	/* the current field */
340*8681Speter     struct nl	*varntnlp;	/* the current variant */
341*8681Speter     struct nl	*vrecnlp;	/* record for the current variant */
342*8681Speter     long	alignment;	/* maximum alignment for any variant */
343*8681Speter 
344*8681Speter     if ( recp == NIL ) {
345*8681Speter 	return;
346*8681Speter     }
347*8681Speter     origin = roundup(offset,recp->align_info);
348*8681Speter     if (origin != offset) {
349*8681Speter 	fprintf(stderr,
350*8681Speter 		"[rec_offsets] offset=%d recp->align_info=%d origin=%d\n",
351*8681Speter 		offset, recp->align_info, origin);
352*8681Speter 	panic("rec_offsets");
353*8681Speter     }
354*8681Speter     DEBUG_RECORDS(
355*8681Speter 	fprintf(stderr,
356*8681Speter 	    "[rec_offsets] offset %d recp->align %d origin %d\n",
357*8681Speter 	    offset, recp->align_info, origin));
358*8681Speter 	/*
359*8681Speter 	 *	fixed fields are forward linked though ->ptr[NL_FIELDLIST]
360*8681Speter 	 *	give them all suitable offsets.
361*8681Speter 	 */
362*8681Speter     for (   fieldnlp = recp->ptr[NL_FIELDLIST];
363*8681Speter 	    fieldnlp != NIL;
364*8681Speter 	    fieldnlp = fieldnlp->ptr[NL_FIELDLIST] ) {
365*8681Speter 	origin = roundup(origin,align(fieldnlp->type));
366*8681Speter 	fieldnlp->value[NL_OFFS] = origin;
367*8681Speter 	DEBUG_RECORDS(
368*8681Speter 	    fprintf(stderr,"[rec_offsets] symbol %s origin %d\n",
369*8681Speter 		    fieldnlp->symbol, origin));
370*8681Speter 	origin += lwidth(fieldnlp->type);
371*8681Speter     }
372*8681Speter 	/*
373*8681Speter 	 *	this is the extent of the record, so far
374*8681Speter 	 */
375*8681Speter     recp->value[NL_OFFS] = origin;
376*8681Speter 	/*
377*8681Speter 	 *	if we have a tag field, we have variants to deal with
378*8681Speter 	 */
379*8681Speter     if ( recp->ptr[NL_TAG] ) {
380*8681Speter 	    /*
381*8681Speter 	     *	if tag field is unnamed, then don't allocate space for it.
382*8681Speter 	     */
383*8681Speter 	fieldnlp = recp->ptr[NL_TAG];
384*8681Speter 	if ( fieldnlp->symbol != NIL ) {
385*8681Speter 	    origin = roundup(origin,align(fieldnlp->type));
386*8681Speter 	    fieldnlp->value[NL_OFFS] = origin;
387*8681Speter 	    DEBUG_RECORDS(fprintf(stderr,"[rec_offsets] tag %s origin\n",
388*8681Speter 				    fieldnlp->symbol, origin));
389*8681Speter 	    origin += lwidth(fieldnlp->type);
390*8681Speter 	}
391*8681Speter 	    /*
392*8681Speter 	     *	find maximum alignment of records of variants
393*8681Speter 	     */
394*8681Speter 	for (	varntnlp = recp->ptr[NL_VARNT];
395*8681Speter 		varntnlp != NIL;
396*8681Speter 		varntnlp = varntnlp -> chain ) {
397*8681Speter 	    vrecnlp = varntnlp->ptr[NL_VTOREC];
398*8681Speter 	    DEBUG_RECORDS(
399*8681Speter 		fprintf(stderr,
400*8681Speter 			"[rec_offsets] maxing variant %d align_info %d\n",
401*8681Speter 			varntnlp->value[0], vrecnlp->align_info));
402*8681Speter 	    origin = roundup(origin,vrecnlp->align_info);
403*8681Speter 	}
404*8681Speter 	DEBUG_RECORDS(
405*8681Speter 	    fprintf(stderr, "[rec_offsets] origin of variants %d\n", origin));
406*8681Speter 	    /*
407*8681Speter 	     *	assign offsets to fields of records of the variants
408*8681Speter 	     *	keep maximum length of the current record.
409*8681Speter 	     */
410*8681Speter 	for (	varntnlp = recp->ptr[NL_VARNT];
411*8681Speter 		varntnlp != NIL;
412*8681Speter 		varntnlp = varntnlp -> chain ) {
413*8681Speter 	    vrecnlp = varntnlp->ptr[NL_VTOREC];
414*8681Speter 		/*
415*8681Speter 		 *	assign offsets to fields of the variant.
416*8681Speter 		 *	recursive call on rec_offsets.
417*8681Speter 		 */
418*8681Speter 	    rec_offsets(vrecnlp,origin);
419*8681Speter 		/*
420*8681Speter 		 *	extent of the record is the
421*8681Speter 		 *	maximum extent of all variants
422*8681Speter 		 */
423*8681Speter 	    if ( vrecnlp->value[NL_OFFS] > recp->value[NL_OFFS] ) {
424*8681Speter 		recp->value[NL_OFFS] = vrecnlp->value[NL_OFFS];
425*8681Speter 	    }
426*8681Speter 	}
427*8681Speter     }
428*8681Speter 	/*
429*8681Speter 	 *	roundup the size of the record to its alignment
430*8681Speter 	 */
431*8681Speter     DEBUG_RECORDS(
432*8681Speter 	fprintf(stderr,
433*8681Speter 		"[rec_offsets] recp->value[NL_OFFS] %d ->align_info %d\n",
434*8681Speter 		recp->value[NL_OFFS], recp->align_info));
435*8681Speter     recp->value[NL_OFFS] = roundup(recp->value[NL_OFFS],recp->align_info);
436*8681Speter }
437