Annotation of 42BSD/ucb/pascal/src/rec.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.