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