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