home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v92.tgz / v92.tar / v92 / src / icont / lglob.c < prev    next >
C/C++ Source or Header  |  1996-03-22  |  11KB  |  387 lines

  1. /*
  2.  * lglob.c -- routines for processing globals.
  3.  */
  4.  
  5. #include "link.h"
  6. #include "tglobals.h"
  7. #include "tproto.h"
  8. #include "opcode.h"
  9. #include "::h:version.h"
  10.  
  11. /*
  12.  * Prototypes.
  13.  */
  14.  
  15. hidden novalue    scanfile    Params((char *filename));
  16. hidden novalue    reference    Params((struct gentry *gp));
  17.  
  18. int nrecords = 0;        /* number of records in program */
  19.  
  20. /*
  21.  * readglob reads the global information from infile (.u2) and merges it with
  22.  *  the global table and record table.
  23.  */
  24. novalue readglob()
  25.    {
  26.    register word id;
  27.    register int n, op;
  28.    int k;
  29.    int implicit;
  30.    char *name;
  31.    struct gentry *gp;
  32.    extern char *progname;
  33.  
  34.    if (getopc(&name) != Op_Version)
  35.       quitf("ucode file %s has no version identification",inname);
  36.    id = getid();        /* get version number of ucode */
  37.    newline();
  38.    if (strcmp(&lsspace[id],UVersion)) {
  39.       fprintf(stderr,"version mismatch in ucode file %s\n",inname);
  40.       fprintf(stderr,"\tucode version: %s\n",&lsspace[id]);
  41.       fprintf(stderr,"\texpected version: %s\n",UVersion);
  42.  
  43.  
  44.       exit(ErrorExit);
  45.  
  46.       }
  47.    while ((op = getopc(&name)) != EOF) {
  48.       switch (op) {
  49.          case Op_Record:    /* a record declaration */
  50.             id = getid();    /* record name */
  51.             n = getdec();    /* number of fields */
  52.             newline();
  53.             gp = glocate(id);
  54.             /*
  55.              * It's ok if the name isn't already in use or if the
  56.              *  name is just used in a "global" declaration.  Otherwise,
  57.              *  it is an inconsistent redeclaration.
  58.              */
  59.             if (gp == NULL || (gp->g_flag & ~F_Global) == 0) {
  60.                gp = putglobal(id, F_Record, n, ++nrecords);
  61.                while (n--) {    /* loop reading field numbers and names */
  62.                   k = getdec();
  63.                   putfield(getid(), gp, k);
  64.                   newline();
  65.                   }
  66.                }
  67.             else {
  68.                lfatal(&lsspace[id], "inconsistent redeclaration");
  69.                while (n--)
  70.                   newline();
  71.                }
  72.             break;
  73.  
  74.          case Op_Impl:        /* undeclared identifiers should be noted */
  75.             if (getopc(&name) == Op_Local)
  76.                implicit = 0;
  77.             else
  78.                implicit = F_ImpError;
  79.             break;
  80.  
  81.          case Op_Trace:        /* turn on tracing */
  82.             trace = -1;
  83.             break;
  84.  
  85.          case Op_Global:    /* global variable declarations */
  86.             n = getdec();    /* number of global declarations */
  87.             newline();
  88.             while (n--) {    /* process each declaration */
  89.                getdec();    /* throw away sequence number */
  90.                k = getoct();    /* get flags */
  91.                if (k & F_Proc)
  92.                   k |= implicit;
  93.                id = getid();    /* get variable name */
  94.                gp = glocate(id);
  95.                /*
  96.                 * Check for conflicting declarations and install the
  97.                 *  variable.
  98.                 */
  99.                if (gp != NULL && (k & F_Proc) && gp->g_flag != F_Global)
  100.                   lfatal(&lsspace[id], "inconsistent redeclaration");
  101.                else if (gp == NULL || (k & F_Proc))
  102.                   putglobal(id, k, getdec(), 0);
  103.                newline();
  104.                }
  105.             break;
  106.  
  107.          case Op_Invocable:    /* "invocable" declaration */
  108.             id = getid();    /* get name */
  109.             if (lsspace[id] == '0')
  110.                strinv = 1;    /* name of "0" means "invocable all" */
  111.             else
  112.                addinvk(&lsspace[id], 2);
  113.             newline();
  114.             break;
  115.  
  116.          case Op_Link:        /* link the named file */
  117.             name = &lsspace[getrest()];    /* get the name and */
  118.  
  119. #if ARM
  120.             {
  121.                 char *flipname (char *);
  122.  
  123.                 /* put it on the list of files to link */
  124.                 alsolink(flipname(name));
  125.             }
  126. #else                    /* ARM */
  127.             alsolink(name);    /*  put it on the list of files to link */
  128. #endif                    /* ARM */
  129.  
  130.             newline();
  131.             break;
  132.  
  133.          default:
  134.             quitf("ill-formed global file %s",inname);
  135.          }
  136.       }
  137.    }
  138.  
  139. /*
  140.  * scanrefs - scan .u1 files for references and mark unreferenced globals.
  141.  *
  142.  * Called only if -fs is *not* specified (or implied by "invocable all").
  143.  */
  144. novalue scanrefs()
  145.    {
  146.    int i, n;
  147.    char *t, *old;
  148.    struct fentry *fp, **fpp;
  149.    struct gentry *gp, **gpp;
  150.    struct rentry *rp;
  151.    struct lfile *lf, *lfls;
  152.    struct ientry *ip, *ipnext;
  153.    struct invkl *inv;
  154.  
  155.    /*
  156.     * Loop through .u1 files and accumulate reference lists.
  157.     */
  158.    lfls = llfiles;
  159. #if SCCX_MX
  160.    while( (lf = getlfile(&lfls)) != 0)
  161. #else
  162.    while (lf = getlfile(&lfls))
  163. #endif
  164.       scanfile(lf->lf_name);
  165.    lstatics = 0;            /* discard accumulated statics */
  166.  
  167.    /*
  168.     * Mark every global as unreferenced.
  169.     */
  170.    for (gp = lgfirst; gp != NULL; gp = gp->g_next)
  171.       gp->g_flag |= F_Unref;
  172.  
  173.    /*
  174.     * Clear the F_Unref flag for referenced globals, starting with main()
  175.     * and marking references within procedures recursively.
  176.     */
  177.    reference(lgfirst);
  178.  
  179.    /*
  180.     * Reference (recursively) every global declared to be "invocable".
  181.     */
  182.    for (inv = invkls; inv != NULL; inv = inv->iv_link)
  183.       if ((gp = glocate(instid(inv->iv_name))) != NULL)
  184.          reference(gp);
  185.  
  186.    /*
  187.     * Rebuild the global list to include only referenced globals,
  188.     * and renumber them.  Also renumber all record constructors.
  189.     * Free all reference lists.
  190.     */
  191.    n = 0;
  192.    nrecords = 0;
  193.    gpp = &lgfirst;
  194.    while ((gp = *gpp) != NULL) {
  195.       if (gp->g_refs != NULL) {
  196.          free((char *)gp->g_refs);        /* free the reference list */
  197.          gp->g_refs = NULL;
  198.          }
  199.       if (gp->g_flag & F_Unref) {
  200.          /*
  201.           *  Global is not referenced anywhere.
  202.           */
  203.          gp->g_index = gp->g_procid = -1;    /* flag as unused */
  204.          if (verbose >= 3) {
  205.             if (gp->g_flag & F_Proc)
  206.                t = "procedure";
  207.             else if (gp->g_flag & F_Record)
  208.                t = "record   ";
  209.             else
  210.                t = "global   ";
  211.             if (!(gp->g_flag & F_Builtin))
  212.                fprintf(stderr, "  discarding %s %s\n", t, &lsspace[gp->g_name]);
  213.             }
  214.          *gpp = gp->g_next;
  215.          }
  216.       else {
  217.          /*
  218.           *  The global is used.  Assign it new serial number(s).
  219.           */
  220.          gp->g_index = n++;
  221.          if (gp->g_flag & F_Record)
  222.             gp->g_procid = ++nrecords;
  223.          gpp = &gp->g_next;
  224.          }
  225.       }
  226.  
  227.    /*
  228.     * Rebuild the field list to include only referenced fields,
  229.     * and renumber them.
  230.     */
  231.    n = 0;
  232.    fpp = &lffirst;
  233.    while ((fp = *fpp) != NULL) {
  234.       for (rp = fp->f_rlist; rp != NULL; rp = rp->r_link)
  235.          if (rp->r_gp->g_procid > 0)    /* if record was referenced */
  236.             break;
  237.       if (rp == NULL) {
  238.          /*
  239.           *  The field was used only in unreferenced record constructors.
  240.           */
  241.          fp->f_fid = 0;
  242.          *fpp = fp->f_nextentry;
  243.          }
  244.       else {
  245.          /*
  246.           *  The field was referenced.  Give it the next number.
  247.           */
  248.          fp->f_fid = ++n;
  249.          fpp = &fp->f_nextentry;
  250.          }
  251.       }
  252.  
  253.    /*
  254.     * Create a new, empty string space, saving a pointer to the old one.
  255.     * Clear the old identifier hash table.
  256.     */
  257.    old = lsspace;
  258.    lsspace = (char *)tcalloc(stsize, 1);
  259.    lsfree = 0;
  260.    for (i = 0; i < ihsize; i++) {
  261.       for (ip = lihash[i]; ip != NULL; ip = ipnext) {
  262.          ipnext = ip->i_blink;
  263.          free((char *)ip);
  264.          }
  265.       lihash[i] = NULL;
  266.       }
  267.  
  268.    /*
  269.     * Reinstall the global identifiers that are actually referenced.
  270.     * This changes the hashing, so clear and rebuild the hash table.
  271.     */
  272.    for (i = 0; i < ghsize; i++)
  273.       lghash[i] = NULL;
  274.    for (gp = lgfirst; gp != NULL; gp = gp->g_next) {
  275.       gp->g_name = instid(&old[gp->g_name]);
  276.       i = ghasher(gp->g_name);
  277.       gp->g_blink = lghash[i];
  278.       lghash[i] = gp;
  279.       }
  280.  
  281.    /*
  282.     * Reinstall the referenced record fields in similar fashion.
  283.     */
  284.    for (i = 0; i < fhsize; i++)
  285.       lfhash[i] = NULL;
  286.    for (fp = lffirst; fp != NULL; fp = fp->f_nextentry) {
  287.       fp->f_name = instid(&old[fp->f_name]);
  288.       i = fhasher(fp->f_name);
  289.       fp->f_blink = lfhash[i];
  290.       lfhash[i] = fp;
  291.       }
  292.  
  293.    /*
  294.     * Free the old string space.
  295.     */
  296.    free((char *)old);
  297.    }
  298.  
  299. /*
  300.  * scanfile -- scan one file for references.
  301.  */
  302. static novalue scanfile(filename)
  303. char *filename;
  304.    {
  305.    int i, k, f, op, nrefs, flags;
  306.    word id, procid;
  307.    char *name;
  308.    struct gentry *gp, **rp;
  309.  
  310.    makename(inname, SourceDir, filename, U1Suffix);
  311.  
  312. #if MVS || VM
  313.    infile = fopen(inname, ReadBinary);
  314.    if (infile != NULL)        /* discard the extra blank we had */
  315.       (void)getc(infile);    /* to write to make it non-empty  */
  316. #else                    /* MVS || VM */
  317.    infile = fopen(inname, ReadText);
  318. #endif                    /* MVS || VM */
  319.  
  320.    if (infile == NULL)
  321.       quitf("cannot open %s", inname);
  322.  
  323.    while ((op = getopc(&name)) != EOF) {
  324.       switch (op) {
  325.          case Op_Proc:
  326.             procid = getid();
  327.             newline();
  328.             gp = glocate(procid);
  329.             locinit();
  330.             nrefs = 0;
  331.             break;
  332.          case Op_Local:
  333.             k = getdec();
  334.             flags = getoct();
  335.             id = getid();
  336.             putlocal(k, id, flags, 0, procid);
  337.             lltable[k].l_flag |= F_Unref;
  338.             break;
  339.          case Op_Var:
  340.             k = getdec();
  341.             newline();
  342.             f = lltable[k].l_flag;
  343.             if ((f & F_Global) && (f & F_Unref)) {
  344.                lltable[k].l_flag = f & ~F_Unref;
  345.                nrefs++;
  346.                }
  347.             break;
  348.          case Op_End:
  349.             newline();
  350.             if (nrefs > 0) {
  351.                rp = (struct gentry **)tcalloc(nrefs + 1, sizeof(*rp));
  352.                gp->g_refs = rp;
  353.                for (i = 0; i <= nlocal; i++)
  354.                   if ((lltable[i].l_flag & (F_Unref + F_Global)) == F_Global)
  355.                      *rp++ = lltable[i].l_val.global;
  356.                *rp = NULL;
  357.                }
  358.             break;
  359.          default:
  360.             newline();
  361.             break;
  362.          }
  363.       }
  364.  
  365.    fclose(infile);
  366.    }
  367.  
  368. /*
  369.  *
  370.  */
  371. static novalue reference(gp)
  372. struct gentry *gp;
  373.    {
  374.    struct gentry **rp;
  375.  
  376.    if (gp->g_flag & F_Unref) {
  377.       gp->g_flag &= ~F_Unref;
  378.       if ((rp = gp->g_refs) != NULL)
  379. #if SCCX_MX
  380.          while( (gp = *rp++) != 0)
  381. #else
  382.          while (gp = *rp++)
  383. #endif
  384.             reference(gp);
  385.       }
  386.    }
  387.