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 / ipl / progs / utrim.icn < prev    next >
Text File  |  2000-07-29  |  6KB  |  209 lines

  1. ############################################################################
  2. #
  3. #    File:     utrim.icn
  4. #
  5. #    Subject:  Program to remove unneeded procs from ucode
  6. #
  7. #    Author:   Gregg M. Townsend
  8. #
  9. #    Date:     August 7, 1993
  10. #
  11. ############################################################################
  12. #
  13. #   This file is in the public domain.
  14. #
  15. ############################################################################
  16. #
  17. #  Usage:  utrim [-s | -v] file...
  18. #
  19. #  Utrim alters a set of uncode files comprising a complete Icon program
  20. #  by removing unreferenced procedures.  The resulting files are smaller,
  21. #  and they produce a smaller icode file.
  22. #
  23. #  The basename of each command argument is used to find a pair of
  24. #  .u1 and .u2 files; each pair is renamed to .u1o and .u2o and
  25. #  replaced by new .u1 and .u2 files.
  26. #
  27. #  -s invokes silent mode; -v invokes verbose mode.
  28. #
  29. #  Warning: utrim may break programs that use string invocation.
  30. #
  31. ############################################################################
  32. #
  33. #  Links: options
  34. #
  35. ############################################################################
  36.  
  37. link options
  38.  
  39. record prc(name, size, calls, need)    # proc record
  40. record lcl(name, flags)            # local record
  41.  
  42. global pnames, ptable            # proc names and table
  43.  
  44.  
  45. # main procedure
  46.  
  47. procedure main(args)
  48.    local opts, fname, name, need
  49.  
  50.    # process options
  51.    opts := options(args, "sv")
  52.    if *args = 0 then
  53.       stop("usage: ", &progname, " [-s | -v] file.u1 ...")
  54.    every !args ?:= tab(upto('.'))
  55.  
  56.    # scan .u1 files to decide what's needed
  57.    pnames := set()
  58.    ptable := table()
  59.    every scan1(!args)
  60.    if /ptable["main"] then
  61.       stop(&progname, ": no main procedure")
  62.    dependencies()
  63.    report(opts)
  64.  
  65.    # write new .u1 and .u2 files
  66.    every fname := !args || (".u1" | ".u2") do {
  67.       remove(fname || "o")
  68.       rename(fname, fname || "o") | stop("can't rename ", fname)
  69.       }
  70.    every filter1(!args)
  71.    every filter2(!args)
  72. end
  73.  
  74.  
  75. #  scan1(fname) -- read .u1 file, add proc names and refs to ptable
  76.  
  77. procedure scan1(fname)
  78.    local u1, line, i, name, flags, curr, locals
  79.    u1 := open(fname || ".u1") | stop(&progname, ": can't open", fname || ".u1")
  80.    while line := read(u1) do line ? {
  81.       if ="proc " then {
  82.          # new proc: make table entry
  83.          name := tab(0)
  84.          insert(pnames, name)
  85.          ptable[name] := curr := prc(name, 0, set())
  86.          locals := []
  87.          }
  88.       else if ="\tlocal\t" then {
  89.          # new local: remember its name
  90.          i := tab(many(&digits))
  91.          =","
  92.          flags := tab(upto(','))
  93.          =","
  94.          name := tab(0)
  95.          put(locals, lcl(name, flags))
  96.          }
  97.       else if ="\tvar\t" then {
  98.          # ref to "local": note as needed if it's a global
  99.          i := tab(0) + 1
  100.          if locals[i].flags = 0 then
  101.             insert(curr.calls, locals[i].name)
  102.          }
  103.       curr.size +:= 1        # tally number of lines
  104.       }
  105.    close(u1)
  106.    return
  107. end
  108.  
  109.  
  110. #  dependencies() -- mark procs called directly or indirectly from main proc
  111.  
  112. procedure dependencies()
  113.    local need, p
  114.  
  115.    need := ["main"]
  116.    while name := get(need) do
  117.       if (p := \ptable[name]) & (/p.need := 1) then
  118.          every put(need, !p.calls)
  119.    return
  120. end
  121.  
  122.  
  123. #  report(opts) -- write reports as selected by command options
  124.  
  125. procedure report(opts)
  126.    local name, p, ptrim, ltrim, ltotal
  127.  
  128.    ltotal := ltrim := ptrim := 0
  129.    every name := !sort(pnames) do {
  130.       p := ptable[name]
  131.       ltotal +:= p.size
  132.       if /p.need then {
  133.          ltrim +:= p.size
  134.          ptrim +:= 1
  135.          }
  136.       if /opts["v"] then
  137.          next
  138.       writes(right(p.size, 6))
  139.       writes(if \p.need then " * " else "   ")
  140.       writes(left(p.name, 16))
  141.       every writes(" ", !sort(p.calls))
  142.       write()
  143.       }
  144.    if /opts["s"] then
  145.       write(&errout, "Trimming ", ptrim, "/", *pnames, " procedures (",
  146.          (100 * ptrim + 5) / *pnames, "%), ", ltrim, "/", ltotal, " lines (",
  147.          (100 * ltrim + 5) / ltotal, "%)")
  148.    return
  149. end
  150.  
  151.  
  152. #  filter1(fname) -- filter .u1o file to make new .u1 file
  153. #
  154. #  For each proc body, copy only if marked as needed in ptable.
  155.  
  156. procedure filter1(fname)
  157.    local old, new, line
  158.  
  159.    old := open(fname||".u1o") | stop(&progname, ": can't open", fname||".u1o")
  160.    new := open(fname||".u1","w") | stop(&progname,": can't write",fname||".u1")
  161.  
  162.    while line := read(old) do line ?
  163.       if ="proc " & /ptable[tab(0)].need then            # check new proc
  164.          until (line ? ="\tend") | not (line := read(old))  # skip to proc end
  165.       else
  166.          write(new, line)
  167.    close(old)
  168.    close(new)
  169.    return
  170. end
  171.  
  172.  
  173. #  filter2(fname) -- filter .u2o file to make new .u2 file
  174. #
  175. #  Copy header verbatim; read list of globals, remove procs trimmed from .u1,
  176. #  and write new (renumbered) global list.
  177.  
  178. procedure filter2(fname)
  179.    local old, new, line, n, glist, flags, name, args, p
  180.  
  181.    old := open(fname||".u2o") | stop(&progname, ": can't open ", fname||".u2o")
  182.    new := open(fname||".u2","w") | stop(&progname,": can't write ",fname||".u2")
  183.  
  184.    write(new, read(old)) | stop(&progname, ": empty ", fname || ".u2o")
  185.    while (line := read(old)) & not (line ? ="global") do
  186.       write(new, line)
  187.  
  188.    glist := []
  189.    while line := read(old) do line ? {
  190.       ="\t"
  191.       tab(many(&digits))
  192.       p := &pos
  193.       =","
  194.       flags := tab(upto(','))
  195.       =","
  196.       name := tab(upto(','))
  197.       if flags = 5 & /(\ptable[name]).need then
  198.          next
  199.       tab(p)
  200.       put(glist, tab(0))
  201.       }
  202.    write(new, "global\t", *glist)
  203.    every write(new, "\t", 0 to *glist - 1, get(glist))
  204.  
  205.    close(old)
  206.    close(new)
  207.    return
  208. end
  209.