home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / pascal / src / rec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-16  |  14.1 KB  |  473 lines

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