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:  */
   6: 
   7: #ifndef lint
   8: static char sccsid[] = "@(#)rec.c	5.1 (Berkeley) 6/5/85";
   9: #endif not lint
  10: 
  11: #include "whoami.h"
  12: #include "0.h"
  13: #include "tree.h"
  14: #include "opcode.h"
  15: #include "align.h"
  16: #include "tree_ty.h"
  17: 
  18:     /*
  19:      *	set this to TRUE with adb to turn on record alignment/offset debugging.
  20:      */
  21: bool    debug_records = FALSE;
  22: #define DEBUG_RECORDS(x)    if (debug_records) { x ; } else
  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:  *
  29:  * Each record has a main RECORD entry,
  30:  * with an attached chain of fields as ->chain;
  31:  * these enclude all the fields in all the variants of this record.
  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.
  34:  *
  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.
  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:  *
  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.
  59:  */
  60: 
  61: /*
  62:  * P0 points to the outermost RECORD for name searches.
  63:  */
  64: struct  nl *P0;
  65: 
  66: struct nl *
  67: tyrec(r, off)
  68:     struct tnode *r;
  69:     int       off;
  70: {
  71:     struct nl   *recp;
  72: 
  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);
  80:     rec_offsets(recp, (long) 0);
  81:     return recp;
  82: }
  83: 
  84: /*
  85:  * Define a record namelist entry.
  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.
  92:  */
  93: struct nl *
  94: tyrec1(r, first)
  95:     register struct tnode *r;   /* T_FLDLST */
  96:     bool first;
  97: {
  98:     register struct nl *p, *P0was;
  99: 
 100:     DEBUG_RECORDS(fprintf(stderr,"[tyrec1] first=%d\n", first));
 101:     p = defnl((char *) 0, RECORD, NLNIL, 0);
 102:     P0was = P0;
 103:     if (first)
 104:         P0 = p;
 105: #ifndef PI0
 106:     p->align_info = A_MIN;
 107: #endif
 108:     if (r != TR_NIL) {
 109:         fields(p, r->fldlst.fix_list);
 110:         variants(p, r->fldlst.variant);
 111:     }
 112:     P0 = P0was;
 113:     return (p);
 114: }
 115: 
 116: /*
 117:  * Define the fixed part fields for p.
 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.
 121:  */
 122: fields(p, r)
 123:     struct nl *p;
 124:     struct tnode *r;    /* T_LISTPP */
 125: {
 126:     register struct tnode   *fp, *tp, *ip;
 127:     struct nl   *jp;
 128:     struct nl   *fieldnlp;
 129: 
 130:     DEBUG_RECORDS(fprintf(stderr,"[fields]\n"));
 131:     for (fp = r; fp != TR_NIL; fp = fp->list_node.next) {
 132:         tp = fp->list_node.list;
 133:         if (tp == TR_NIL)
 134:             continue;
 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);
 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;
 158:     }
 159: }
 160: 
 161: /*
 162:  * Define the variants for RECORD p.
 163:  */
 164: variants(p, r)
 165:     struct nl *p;
 166:     register struct tnode *r;   /* T_TYVARPT */
 167: {
 168:     register struct tnode *vc, *v;
 169:     struct nl *vr;
 170:     struct nl *ct;
 171: 
 172:     DEBUG_RECORDS(fprintf(stderr,"[variants]\n"));
 173:     if (r == TR_NIL)
 174:         return;
 175:     ct = gtype(r->varpt.type_id);
 176:     if ( ( ct != NLNIL ) && ( isnta( ct , "bcsi" ) ) ) {
 177:         error("Tag fields cannot be %ss" , nameof( ct ) );
 178:     }
 179:     line = r->varpt.line_no;
 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: 	 */
 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)
 189:             continue;
 190:         vr = tyrec1(v->tyvarnt.fld_list, FALSE);
 191: #ifndef PI0
 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:         }
 199: #endif
 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);
 204:     }
 205: }
 206: 
 207: /*
 208:  * Define a field in subrecord p of record P0
 209:  * with name s and type t.
 210:  */
 211: struct nl *
 212: deffld(p, s, t)
 213:     struct nl *p;
 214:     register char *s;
 215:     register struct nl *t;
 216: {
 217:     register struct nl *fp;
 218: 
 219:     DEBUG_RECORDS(fprintf(stderr,"[deffld] s=<%s>\n", s));
 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:     }
 226:         /*
 227: 	     *	enter the field with its type
 228: 	     */
 229:     fp = enter(defnl(s, FIELD, t, 0));
 230:         /*
 231: 	     *	if no name, then this is an unnamed tag,
 232: 	     *	so don't link it into reclook()'s chain.
 233: 	     */
 234:     if (s != NIL) {
 235:         fp->chain = P0->chain;
 236:         P0->chain = fp;
 237: #ifndef PI0
 238:             /*
 239: 		     * and the alignment is propagated back.
 240: 		     */
 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:         }
 249: #endif
 250:         if (t != NIL) {
 251:             P0->nl_flags |= t->nl_flags & NFILES;
 252:             p->nl_flags |= t->nl_flags & NFILES;
 253:         }
 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:  */
 263: struct nl *
 264: defvnt(p, t, vr, ct)
 265:     struct nl *p, *vr;
 266:     struct tnode *t;    /* CHAR_CONST or SIGN_CONST */
 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:     }
 278:     av = defnl((char *) 0, VARNT, ct, 0);
 279: #ifndef PI1
 280:     if (ct != NIL)
 281:         uniqv(p);
 282: #endif not PI1
 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:  */
 295: uniqv(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:  */
 313: struct nl *
 314: reclook(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: }
 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:      */
 344: rec_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 */
 352: 
 353:     if ( recp == NIL ) {
 354:     return;
 355:     }
 356:     origin = roundup((int) offset,(long) recp->align_info);
 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] ) {
 374:     origin = roundup((int) origin,(long) align(fieldnlp->type));
 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 ) {
 394:         origin = roundup((int) origin,(long) align(fieldnlp->type));
 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));
 411:         origin = roundup((int) origin,(long) vrecnlp->align_info);
 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));
 444:     recp->value[NL_OFFS] = roundup(recp->value[NL_OFFS],(long) recp->align_info);
 445: }

Defined functions

deffld defined in line 211; used 3 times
defvnt defined in line 263; used 2 times
fields defined in line 122; used 1 times
rec_offsets defined in line 344; used 2 times
tyrec1 defined in line 93; used 3 times
uniqv defined in line 295; used 1 times
variants defined in line 164; used 1 times

Defined variables

P0 defined in line 64; used 7 times
sccsid defined in line 8; never used

Defined macros

DEBUG_RECORDS defined in line 22; used 13 times
Last modified: 1985-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3266
Valid CSS Valid XHTML 1.0 Strict