Annotation of 43BSDReno/pgrm/pascal/src/rec.c, revision 1.1.1.1

1.1       root        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.2 (Berkeley) 4/6/87";
                      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 %d\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: }

unix.superglobalmegacorp.com

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