xref: /csrg-svn/usr.bin/pascal/src/rec.c (revision 30801)
122187Sdist /*
222187Sdist  * Copyright (c) 1980 Regents of the University of California.
322187Sdist  * All rights reserved.  The Berkeley software License Agreement
422187Sdist  * specifies the terms and conditions for redistribution.
522187Sdist  */
6770Speter 
714741Sthien #ifndef lint
8*30801Sbostic static char sccsid[] = "@(#)rec.c	5.2 (Berkeley) 04/06/87";
922187Sdist #endif not lint
10770Speter 
11770Speter #include "whoami.h"
12770Speter #include "0.h"
13770Speter #include "tree.h"
14770Speter #include "opcode.h"
158681Speter #include "align.h"
1614741Sthien #include "tree_ty.h"
17770Speter 
188681Speter     /*
198681Speter      *	set this to TRUE with adb to turn on record alignment/offset debugging.
208681Speter      */
218681Speter bool	debug_records = FALSE;
228681Speter #define	DEBUG_RECORDS(x)	if (debug_records) { x ; } else
238681Speter 
24770Speter /*
25770Speter  * Build a record namelist entry.
26770Speter  * Some of the processing here is somewhat involved.
27770Speter  * The basic structure we are building is as follows.
28770Speter  *
298681Speter  * Each record has a main RECORD entry,
308681Speter  * with an attached chain of fields as ->chain;
3114741Sthien  * these enclude all the fields in all the variants of this record.
328681Speter  * Fields are cons'ed to the front of the ->chain list as they are discovered.
338681Speter  * This is for reclook(), but not for sizing and aligning offsets.
34770Speter  *
358681Speter  * If there are variants to the record, NL_TAG points to the field which
368681Speter  * is the tag.  If its name is NIL, the tag field is unnamed, and is not
378681Speter  * allocated any space in the record.
38770Speter  * Attached to NL_VARNT is a chain of VARNT structures
39770Speter  * describing each of the variants.  These are further linked
40770Speter  * through ->chain.  Each VARNT has, in ->range[0] the value of
41770Speter  * the associated constant, and each points at a RECORD describing
42770Speter  * the subrecord through NL_VTOREC.  These pointers are not unique,
43770Speter  * more than one VARNT may reference the same RECORD.
44770Speter  *
458681Speter  * On the first pass, we traverse the parse tree and construct the namelist
468681Speter  * entries.  This pass fills in the alignment of each record (including
478681Speter  * subrecords (the alignment of a record is the maximum of the alignments
488681Speter  * of any of its fields).
498681Speter  * A second pass over the namelist entries fills in the offsets of each field
508681Speter  * based on the alignments required.  This second pass uses the NL_FIELDLIST
518681Speter  * chaining of fields, and the NL_TAG pointer and the NL_VARNT pointer to get
528681Speter  * to fields in the order in which they were declared.
538681Speter  * This second pass can not be folded into the first pass,
548681Speter  * as the starting offset of all variants is the same,
558681Speter  * so we must see all the variants (and especially must know their alignments)
568681Speter  * before assigning offsets.  With the alignments calculated (by the first
578681Speter  * pass) this can be done in one top down pass, max'ing over the alignment of
588681Speter  * variants before assigning offsets to any of them.
59770Speter  */
60770Speter 
61770Speter /*
62770Speter  * P0 points to the outermost RECORD for name searches.
63770Speter  */
64770Speter struct	nl *P0;
65770Speter 
668681Speter struct nl *
67770Speter tyrec(r, off)
6814741Sthien 	struct tnode *r;
6914741Sthien 	int	      off;
70770Speter {
718681Speter 	struct nl	*recp;
72770Speter 
738681Speter 	DEBUG_RECORDS(fprintf(stderr,"[tyrec] off=%d\n", off));
748681Speter 	    /*
758681Speter 	     *	build namelist structure for the outermost record type.
768681Speter 	     *	then calculate offsets (starting at 0) of the fields
778681Speter 	     *	in this record and its variant subrecords.
788681Speter 	     */
798681Speter 	recp = tyrec1(r, TRUE);
8014741Sthien 	rec_offsets(recp, (long) 0);
818681Speter 	return recp;
82770Speter }
83770Speter 
84770Speter /*
85770Speter  * Define a record namelist entry.
868681Speter  * r is the tree for the record to be built.
878681Speter  * first is a boolean indicating whether this is an outermost record,
888681Speter  * for name lookups.
898681Speter  * p is the record we define here.
908681Speter  * P0was is a local which stacks the enclosing value of P0 in the stack frame,
918681Speter  * since tyrec1() is recursive.
92770Speter  */
93770Speter struct nl *
948681Speter tyrec1(r, first)
9514741Sthien 	register struct tnode *r;	/* T_FLDLST */
968681Speter 	bool first;
97770Speter {
98770Speter 	register struct nl *p, *P0was;
99770Speter 
1008681Speter 	DEBUG_RECORDS(fprintf(stderr,"[tyrec1] first=%d\n", first));
10114741Sthien 	p = defnl((char *) 0, RECORD, NLNIL, 0);
102770Speter 	P0was = P0;
103770Speter 	if (first)
104770Speter 		P0 = p;
105770Speter #ifndef PI0
1068681Speter 	p->align_info = A_MIN;
107770Speter #endif
10814741Sthien 	if (r != TR_NIL) {
10914741Sthien 		fields(p, r->fldlst.fix_list);
11014741Sthien 		variants(p, r->fldlst.variant);
111770Speter 	}
112770Speter 	P0 = P0was;
113770Speter 	return (p);
114770Speter }
115770Speter 
116770Speter /*
117770Speter  * Define the fixed part fields for p.
1188681Speter  * hang them, in order, from the record entry, through ->ptr[NL_FIELDLIST].
1198681Speter  * the fieldlist is a tconc structure, and is manipulated
1208681Speter  * just like newlist(), addlist(), fixlist() in the parser.
121770Speter  */
122770Speter fields(p, r)
123770Speter 	struct nl *p;
12414741Sthien 	struct tnode *r;	/* T_LISTPP */
125770Speter {
12614741Sthien 	register struct tnode	*fp, *tp, *ip;
1278681Speter 	struct nl	*jp;
1288681Speter 	struct nl	*fieldnlp;
129770Speter 
1308681Speter 	DEBUG_RECORDS(fprintf(stderr,"[fields]\n"));
13114741Sthien 	for (fp = r; fp != TR_NIL; fp = fp->list_node.next) {
13214741Sthien 		tp = fp->list_node.list;
13314741Sthien 		if (tp == TR_NIL)
134770Speter 			continue;
13514741Sthien 		jp = gtype(tp->rfield.type);
13614741Sthien 		line = tp->rfield.line_no;
13714741Sthien 		for (ip = tp->rfield.id_list; ip != TR_NIL;
13814741Sthien 				    ip = ip->list_node.next) {
13914741Sthien 		    fieldnlp = deffld(p, (char *) ip->list_node.list, jp);
1408681Speter 		    if ( p->ptr[NL_FIELDLIST] == NIL ) {
1418681Speter 			    /* newlist */
1428681Speter 			p->ptr[NL_FIELDLIST] = fieldnlp;
1438681Speter 			fieldnlp->ptr[NL_FIELDLIST] = fieldnlp;
1448681Speter 		    } else {
1458681Speter 			    /* addlist */
1468681Speter 			fieldnlp->ptr[NL_FIELDLIST] =
1478681Speter 				p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST];
1488681Speter 			p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = fieldnlp;
1498681Speter 			p->ptr[NL_FIELDLIST] = fieldnlp;
1508681Speter 		    }
1518681Speter 		}
152770Speter 	}
1538681Speter 	if ( p->ptr[NL_FIELDLIST] != NIL ) {
1548681Speter 		/* fixlist */
1558681Speter 	    fieldnlp = p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST];
1568681Speter 	    p->ptr[NL_FIELDLIST]->ptr[NL_FIELDLIST] = NIL;
1578681Speter 	    p->ptr[NL_FIELDLIST] = fieldnlp;
1588681Speter 	}
159770Speter }
160770Speter 
161770Speter /*
162770Speter  * Define the variants for RECORD p.
163770Speter  */
164770Speter variants(p, r)
165770Speter 	struct nl *p;
16614741Sthien 	register struct tnode *r;	/* T_TYVARPT */
167770Speter {
16814741Sthien 	register struct tnode *vc, *v;
16914741Sthien 	struct nl *vr;
170770Speter 	struct nl *ct;
171770Speter 
1728681Speter 	DEBUG_RECORDS(fprintf(stderr,"[variants]\n"));
17314741Sthien 	if (r == TR_NIL)
174770Speter 		return;
17514741Sthien 	ct = gtype(r->varpt.type_id);
17614741Sthien 	if ( ( ct != NLNIL ) && ( isnta( ct , "bcsi" ) ) ) {
177770Speter 	    error("Tag fields cannot be %ss" , nameof( ct ) );
178770Speter 	}
17914741Sthien 	line = r->varpt.line_no;
180770Speter 	/*
181770Speter 	 * Want it even if r[2] is NIL so
182770Speter 	 * we check its type in "new" and "dispose"
183770Speter 	 * calls -- link it to NL_TAG.
184770Speter 	 */
18514741Sthien 	p->ptr[NL_TAG] = deffld(p, r->varpt.cptr, ct);
18614741Sthien 	for (vc = r->varpt.var_list; vc != TR_NIL; vc = vc->list_node.next) {
18714741Sthien 		v = vc->list_node.list;
18814741Sthien 		if (v == TR_NIL)
189770Speter 			continue;
19014741Sthien 		vr = tyrec1(v->tyvarnt.fld_list, FALSE);
191770Speter #ifndef PI0
1928681Speter 		DEBUG_RECORDS(
1938681Speter 		    fprintf(stderr,
1948681Speter 			"[variants] p->align_info %d vr->align_info %d\n",
1958681Speter 			p->align_info, vr->align_info));
1968681Speter 		if (vr->align_info > p->align_info) {
1978681Speter 		    p->align_info = vr->align_info;
1988681Speter 		}
199770Speter #endif
20014741Sthien 		line = v->tyvarnt.line_no;
20114741Sthien 		for (v = v->tyvarnt.const_list; v != TR_NIL;
20214741Sthien 				v = v->list_node.next)
20314741Sthien 			(void) defvnt(p, v->list_node.list, vr, ct);
204770Speter 	}
205770Speter }
206770Speter 
207770Speter /*
208770Speter  * Define a field in subrecord p of record P0
209770Speter  * with name s and type t.
210770Speter  */
211770Speter struct nl *
212770Speter deffld(p, s, t)
213770Speter 	struct nl *p;
214770Speter 	register char *s;
215770Speter 	register struct nl *t;
216770Speter {
217770Speter 	register struct nl *fp;
218770Speter 
2198681Speter 	DEBUG_RECORDS(fprintf(stderr,"[deffld] s=<%s>\n", s));
220770Speter 	if (reclook(P0, s) != NIL) {
221770Speter #ifndef PI1
222770Speter 		error("%s is a duplicate field name in this record", s);
223770Speter #endif
224770Speter 		s = NIL;
225770Speter 	}
226770Speter 	    /*
2278681Speter 	     *	enter the field with its type
228770Speter 	     */
229770Speter 	fp = enter(defnl(s, FIELD, t, 0));
2308681Speter 	    /*
2318681Speter 	     *	if no name, then this is an unnamed tag,
2328681Speter 	     *	so don't link it into reclook()'s chain.
2338681Speter 	     */
234770Speter 	if (s != NIL) {
235770Speter 		fp->chain = P0->chain;
236770Speter 		P0->chain = fp;
237770Speter #ifndef PI0
238770Speter 		    /*
2398681Speter 		     * and the alignment is propagated back.
240770Speter 		     */
2418681Speter 		fp->align_info = align(t);
2428681Speter 		DEBUG_RECORDS(
2438681Speter 		    fprintf(stderr,
2448681Speter 			"[deffld] fp->align_info %d p->align_info %d \n",
2458681Speter 			fp->align_info, p->align_info));
2468681Speter 		if (fp->align_info > p->align_info) {
2478681Speter 		    p->align_info = fp->align_info;
2488681Speter 		}
249770Speter #endif
250770Speter 		if (t != NIL) {
251770Speter 			P0->nl_flags |= t->nl_flags & NFILES;
252770Speter 			p->nl_flags |= t->nl_flags & NFILES;
253770Speter 		}
254770Speter 	}
255770Speter 	return (fp);
256770Speter }
257770Speter 
258770Speter /*
259770Speter  * Define a variant from the constant tree of t
260770Speter  * in subrecord p of record P0 where the casetype
261770Speter  * is ct and the variant record to be associated is vr.
262770Speter  */
263770Speter struct nl *
264770Speter defvnt(p, t, vr, ct)
265770Speter 	struct nl *p, *vr;
26614741Sthien 	struct tnode *t;	/* CHAR_CONST or SIGN_CONST */
267770Speter 	register struct nl *ct;
268770Speter {
269770Speter 	register struct nl *av;
270770Speter 
271770Speter 	gconst(t);
272770Speter 	if (ct != NIL && incompat(con.ctype, ct , t )) {
273770Speter #ifndef PI1
274770Speter 		cerror("Variant label type incompatible with selector type");
275770Speter #endif
276770Speter 		ct = NIL;
277770Speter 	}
27814741Sthien 	av = defnl((char *) 0, VARNT, ct, 0);
279770Speter #ifndef PI1
280770Speter 	if (ct != NIL)
281770Speter 		uniqv(p);
2828681Speter #endif not PI1
283770Speter 	av->chain = p->ptr[NL_VARNT];
284770Speter 	p->ptr[NL_VARNT] = av;
285770Speter 	av->ptr[NL_VTOREC] = vr;
286770Speter 	av->range[0] = con.crval;
287770Speter 	return (av);
288770Speter }
289770Speter 
290770Speter #ifndef PI1
291770Speter /*
292770Speter  * Check that the constant label value
293770Speter  * is unique among the labels in this variant.
294770Speter  */
295770Speter uniqv(p)
296770Speter 	struct nl *p;
297770Speter {
298770Speter 	register struct nl *vt;
299770Speter 
300770Speter 	for (vt = p->ptr[NL_VARNT]; vt != NIL; vt = vt->chain)
301770Speter 		if (vt->range[0] == con.crval) {
302770Speter 			error("Duplicate variant case label in record");
303770Speter 			return;
304770Speter 		}
305770Speter }
306770Speter #endif
307770Speter 
308770Speter /*
309770Speter  * See if the field name s is defined
310770Speter  * in the record p, returning a pointer
311770Speter  * to it namelist entry if it is.
312770Speter  */
313770Speter struct nl *
314770Speter reclook(p, s)
315770Speter 	register struct nl *p;
316770Speter 	char *s;
317770Speter {
318770Speter 
319770Speter 	if (p == NIL || s == NIL)
320770Speter 		return (NIL);
321770Speter 	for (p = p->chain; p != NIL; p = p->chain)
322770Speter 		if (p->symbol == s)
323770Speter 			return (p);
324770Speter 	return (NIL);
325770Speter }
3268681Speter 
3278681Speter     /*
3288681Speter      *	descend namelist entry for a record and assign offsets.
3298681Speter      *	fields go at the next higher offset that suits their alignment.
3308681Speter      *	all variants of a record start at the same offset, which is suitable
3318681Speter      *	for the alignment of their worst aligned field.  thus the size of a
3328681Speter      *	record is independent of whether or not it is a variant
3338681Speter      *	(a desirable property).
3348681Speter      *	records come to us in the namelist, where they have been annotated
3358681Speter      *	with the maximum alignment their fields require.
3368681Speter      *	the starting offset is passed to us, and is passed recursively for
3378681Speter      *	variant records within records.
3388681Speter      *	the final maximum size of each record is recorded in the namelist
3398681Speter      *	in the value[NL_OFFS] field of the namelist for the record.
3408681Speter      *
3418681Speter      *	this is supposed to match the offsets used by the c compiler
3428681Speter      *	so people can share records between modules in both languages.
3438681Speter      */
3448681Speter rec_offsets(recp, offset)
3458681Speter     struct nl	*recp;		/* pointer to the namelist record */
3468681Speter     long	offset;		/* starting offset for this record/field */
3478681Speter {
3488681Speter     long	origin;		/* offset of next field */
3498681Speter     struct nl	*fieldnlp;	/* the current field */
3508681Speter     struct nl	*varntnlp;	/* the current variant */
3518681Speter     struct nl	*vrecnlp;	/* record for the current variant */
3528681Speter 
3538681Speter     if ( recp == NIL ) {
3548681Speter 	return;
3558681Speter     }
35614741Sthien     origin = roundup((int) offset,(long) recp->align_info);
3578681Speter     if (origin != offset) {
3588681Speter 	fprintf(stderr,
3598681Speter 		"[rec_offsets] offset=%d recp->align_info=%d origin=%d\n",
3608681Speter 		offset, recp->align_info, origin);
3618681Speter 	panic("rec_offsets");
3628681Speter     }
3638681Speter     DEBUG_RECORDS(
3648681Speter 	fprintf(stderr,
3658681Speter 	    "[rec_offsets] offset %d recp->align %d origin %d\n",
3668681Speter 	    offset, recp->align_info, origin));
3678681Speter 	/*
3688681Speter 	 *	fixed fields are forward linked though ->ptr[NL_FIELDLIST]
3698681Speter 	 *	give them all suitable offsets.
3708681Speter 	 */
3718681Speter     for (   fieldnlp = recp->ptr[NL_FIELDLIST];
3728681Speter 	    fieldnlp != NIL;
3738681Speter 	    fieldnlp = fieldnlp->ptr[NL_FIELDLIST] ) {
37414741Sthien 	origin = roundup((int) origin,(long) align(fieldnlp->type));
3758681Speter 	fieldnlp->value[NL_OFFS] = origin;
3768681Speter 	DEBUG_RECORDS(
3778681Speter 	    fprintf(stderr,"[rec_offsets] symbol %s origin %d\n",
3788681Speter 		    fieldnlp->symbol, origin));
3798681Speter 	origin += lwidth(fieldnlp->type);
3808681Speter     }
3818681Speter 	/*
3828681Speter 	 *	this is the extent of the record, so far
3838681Speter 	 */
3848681Speter     recp->value[NL_OFFS] = origin;
3858681Speter 	/*
3868681Speter 	 *	if we have a tag field, we have variants to deal with
3878681Speter 	 */
3888681Speter     if ( recp->ptr[NL_TAG] ) {
3898681Speter 	    /*
3908681Speter 	     *	if tag field is unnamed, then don't allocate space for it.
3918681Speter 	     */
3928681Speter 	fieldnlp = recp->ptr[NL_TAG];
3938681Speter 	if ( fieldnlp->symbol != NIL ) {
39414741Sthien 	    origin = roundup((int) origin,(long) align(fieldnlp->type));
3958681Speter 	    fieldnlp->value[NL_OFFS] = origin;
396*30801Sbostic 	    DEBUG_RECORDS(fprintf(stderr,"[rec_offsets] tag %s origin %d\n",
3978681Speter 				    fieldnlp->symbol, origin));
3988681Speter 	    origin += lwidth(fieldnlp->type);
3998681Speter 	}
4008681Speter 	    /*
4018681Speter 	     *	find maximum alignment of records of variants
4028681Speter 	     */
4038681Speter 	for (	varntnlp = recp->ptr[NL_VARNT];
4048681Speter 		varntnlp != NIL;
4058681Speter 		varntnlp = varntnlp -> chain ) {
4068681Speter 	    vrecnlp = varntnlp->ptr[NL_VTOREC];
4078681Speter 	    DEBUG_RECORDS(
4088681Speter 		fprintf(stderr,
4098681Speter 			"[rec_offsets] maxing variant %d align_info %d\n",
4108681Speter 			varntnlp->value[0], vrecnlp->align_info));
41114741Sthien 	    origin = roundup((int) origin,(long) vrecnlp->align_info);
4128681Speter 	}
4138681Speter 	DEBUG_RECORDS(
4148681Speter 	    fprintf(stderr, "[rec_offsets] origin of variants %d\n", origin));
4158681Speter 	    /*
4168681Speter 	     *	assign offsets to fields of records of the variants
4178681Speter 	     *	keep maximum length of the current record.
4188681Speter 	     */
4198681Speter 	for (	varntnlp = recp->ptr[NL_VARNT];
4208681Speter 		varntnlp != NIL;
4218681Speter 		varntnlp = varntnlp -> chain ) {
4228681Speter 	    vrecnlp = varntnlp->ptr[NL_VTOREC];
4238681Speter 		/*
4248681Speter 		 *	assign offsets to fields of the variant.
4258681Speter 		 *	recursive call on rec_offsets.
4268681Speter 		 */
4278681Speter 	    rec_offsets(vrecnlp,origin);
4288681Speter 		/*
4298681Speter 		 *	extent of the record is the
4308681Speter 		 *	maximum extent of all variants
4318681Speter 		 */
4328681Speter 	    if ( vrecnlp->value[NL_OFFS] > recp->value[NL_OFFS] ) {
4338681Speter 		recp->value[NL_OFFS] = vrecnlp->value[NL_OFFS];
4348681Speter 	    }
4358681Speter 	}
4368681Speter     }
4378681Speter 	/*
4388681Speter 	 *	roundup the size of the record to its alignment
4398681Speter 	 */
4408681Speter     DEBUG_RECORDS(
4418681Speter 	fprintf(stderr,
4428681Speter 		"[rec_offsets] recp->value[NL_OFFS] %d ->align_info %d\n",
4438681Speter 		recp->value[NL_OFFS], recp->align_info));
44414741Sthien     recp->value[NL_OFFS] = roundup(recp->value[NL_OFFS],(long) recp->align_info);
4458681Speter }
446