############################################################################
#
#	File:     toktab.icn
#
#	Subject:  Program to summarize Icon token counts
#
#	Author:   Ralph E. Griswold
#
#	Date:     June 21, 1994
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#  This program reads the token files given on the command line and
#  summarizes them in a single file.
#
#  The supported options are:
#
#	-n	sort tokens by category in decreasing numerical order;
#		   default alphabetical sorting
#	-l i	limit output in any category to i items; default no limit
#
############################################################################
#
#  Links:  options, showtbl
#
############################################################################

link options
link showtbl

global binops, unops, vars, controls, procs, others, keys
global clits, ilits, rlits, slits
global summary, globals, locals, statics, declarations, fields, files, parms
global fldref

procedure main(args)
   local names, tables, i, file, input, count, line, tbl, opts, k, limit
   local total, result

   opts := options(args, "nl+")
   k := if \opts["n"] then "val" else "ref"
   limit := \opts["l"] | 2 ^ 31

   total := 0

   # WARNING:  The following data must match the data in tokgen.icn.
   #           Ideally, they both should work from an include file.
   #           Later ...

   #  Build a list of tables for the different types of tokens.  The order
   #  of the tables determines the order of output.

   tables := []
   every put(tables, (unops | binops | others | controls | keys | clits | 
      ilits | rlits | slits | vars | fldref | declarations | globals |
      locals | statics | parms | fields | files) := table(0))

   #  Create a list of names for the different types of tokens.  The order
   #  of the names must correspond to the order of the tables above.

   names := ["Unary operators", "Binary operators", "Other operations", 
      "Control structures", "Keywords", "Cset literals", "Integer literals",
      "Real literals", "String literals",  "Variable references",
      "Field references", "Declarations", "Globals", "Locals", "Statics",
      "Procedure parameters", "Record fields", "Included files"]

   #  Read the token files

   every file := !args do {
      input := open(file) | stop("*** cannot open ", file)
      read(input)				# get rid of first line
      while line := trim(read(input)) do {
         line ? {
            if ="Total tokens:" then break
            if any(&ucase) & name := tab(upto(':')) & pos(-1) then {
               (tbl := tables[index(names, name)]) |
                  stop("*** invalid token category: ", name)
               read(input)			# get rid of blank line
               next
               }
            if *line = 0 then {
               read(input)			# get rid of "total"
               read(input)			# and blank line
               next
               }
            if tab(upto(&digits)) then {
               count := tab(many(&digits)) | next
               tab(many(' '))
               name := tab(0)
               tbl[name] +:= count
               }
            }
         }
         close(input)
      }

   #  Now output the results

   every i := 1 to *names do {
      result := showtbl(names[i], tables[i], k, limit)
      count := result[1]
      total +:= count
      if result[2] > limit then write("        ...") else write()
      write(right(count, 8), "   total")
      }
   write("\nTotal tokens: ", total)


end

#  This procedure returns the first index in L whose corresponding element
#  is x

procedure index(L, x)
   local i

   every i := 1 to *L do
      if L[i] === x then return i

   fail

end
