############################################################################
#
#	File:     empg.icn
#
#	Subject:  Program to make expression-evaluation programs
#
#	Author:   Ralph E. Griswold
#
#	Date:     December 16, 1998
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#  This program produces a program for evaluating Icon expressions.  The
#  input to this program has three forms, depending on the first character
#  of each line:
#
#	:	the remainder of the line is an expression to be evaluated
#		only once
#
#	%	the remainder of the line is part of a declaration
#
#	#	the remainder of the line is a comment and is ignored
#
#  Anything else is an expression to be evaluated in a loop.
#
#  For example, the input
#
#  # Time record access
#  %record complex(r, i)
#  :z := complex(1.0, 3.5)
#  z.r
#
#  produces a program to time z.r in a loop.

#  The following options are supported:
#
#	-l i	use i for the number of loop iterations, default 100000
#	-d i	use i for the "delta" to adjust timings; otherwise it
#		  is computed when the expression-evaluation program
#		  is run
#
############################################################################
#
#  Links:  options
#
############################################################################

link options

global decls

procedure main(args)
   local line, opts, limit, delcomp

   opts := options(args, "d+l+")

   write("link empgsup")
   write("link options")
   write("procedure main(args)")
   write("   local opts")
   write("   opts := options(args, \"d+l+\")")
   write("   _Limit := ", \opts["l"] | " \\opts[\"l\"] | 100000")
   write("   _Delta := ", \opts["d"] | " \\opts[\"d\"] | _Initialize(_Limit)")
  
   decls := []

   while line := read() do
      line ? {
         if =":" then evaluate(tab(0))
         else if ="%" then declare(tab(0))
         else if ="#" then next
         else timeloop(tab(0))
         }

   write("end")

   every write(!decls)

end

#  Save a declaration line.

procedure declare(line)

   put(decls, line)

   return

end

#  Produce code to just evaluate an expression.

procedure evaluate(expr)

   write("   ", expr)

   return

end

#  Produce code to evaluate an expression in a loop and time it.

procedure timeloop(expr)

   write("   write(", image(expr), ")")
   write("   _Itime := &time")
   write("   every 1 to _Limit do {")
   write("      &null & (", expr, ")")
   write("      }")
   write("   write(real(&time - _Itime -_Delta) / _Limit, \" ms.\")")
   write("   write()")

   return

end
