summaryrefslogtreecommitdiff
path: root/ipl/procs/echo.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/procs/echo.icn')
-rw-r--r--ipl/procs/echo.icn227
1 files changed, 227 insertions, 0 deletions
diff --git a/ipl/procs/echo.icn b/ipl/procs/echo.icn
new file mode 100644
index 0000000..5a90c97
--- /dev/null
+++ b/ipl/procs/echo.icn
@@ -0,0 +1,227 @@
+############################################################################
+#
+# File: echo.icn
+#
+# Subject: Procedure to perform "variable interpolation" a la Perl
+#
+# Authors: Charles L Hethcoat III and Carl Sturtivant
+#
+# Date: February 9, 2010
+#
+############################################################################
+#
+# This file is in the public domain.
+#
+############################################################################
+#
+# echo() substitutes global variables for occurrences of $name in &subject,
+# and writes the result to standard output.
+#
+############################################################################
+#
+# Background:
+#
+# String "interpolation", as used in Perl, Tcl, Bash, and so on,
+# involves a special notation used within a string that causes the
+# value of a variable to be inserted into the string at runtime. A
+# common notation for this is a dollar sign, e. g. "The price is
+# $price pfennig." If a variable named "price" has the value 10, then
+# on output the string becomes "The price is 10 pfennig."
+#
+# Interpolation is lacking in Icon, so we must use the fussier syntax
+# of an Icon write() procedure: write("The price is ", price,
+# "pfennig."). Here is a slightly more complex example, assuming
+# variables `price' = 10, `article' == "thimble", and `currency' ==
+# "pfennig":
+#
+# write("The price of a ", article, " is ", price, " ", currency, ".")
+#
+# This can be annoying and error-prone if we must use many such
+# strings in a program.
+#
+# The echo() procedure provides a very nice solution for Icon
+# programmers. Compare the preceding write() call to this:
+#
+# "The price of a $article is $price $currency" ? echo()
+#
+# Is this not much simpler? Both examples will print out the string
+#
+# "The price of a thimble is 10 pfennig."
+#
+# but interpolation with echo() greatly reduces the low-level
+# syntactic requirements (and reduces the number of characters to type
+# from 68 to 54). It is much easier to write, read, and check. If
+# many such lines of code are needed, the difference adds up.
+# Consider, for example, how this would pay off if your program needs
+# to generate hundreds of lines of HTML or PostScript.
+#
+############################################################################
+#
+# Usage:
+#
+# A string to
+# be printed with interpolated values should be set up in a scanning
+# environment, using echo() as the scanning procedure, as in
+# "foo$variable" ? echo(). Here is an actual example for testing:
+#
+# link echo
+# global month, day, year
+#
+# procedure main()
+# month := "February"
+# day := 30
+# year := 2010
+# "Free beer on $month $day, $year." ? echo()
+# end
+#
+# Assuming echo.icn has been compiled with the -c option beforehand,
+# compiling, linking, and running this program produces the string
+# "Free beer on February 30, 2010." on standard output.
+#
+############################################################################
+#
+# Notes:
+#
+# Since there is no way for any Icon procedure to discover the values of
+# any another procedure's local variables, all variables to be used via
+# the echo() procedure must be global. This restriction ought not to be
+# too serious for smaller programs, or even longer ones if they are of
+# simple construction. But it may be a limitation for sophisticated
+# Icon programming projects. You will have to be the judge.
+#
+# If x is a global variable with value 10,
+#
+# "x" ? echo() prints "x"
+# "$x" ? echo() prints "10"
+# "$$x" ? echo() prints "$x"
+# "$$$x" ? echo() prints "$10"
+# "$$$$x" ? echo() prints "$$x"
+# "$$$$$x" ? echo() prints "$$10"
+#
+# and so on. The rule is: take dollar signs off in pairs from the
+# left. Each pair prints ONE literal dollar sign on the output.
+#
+# If there were an odd number of dollar signs to begin with, then one
+# will be left over, and this will print the value of the variable (10).
+#
+# If there were an even number to begin with, then none are left, and a
+# literal "x" is printed.
+#
+# There is an extended notation that helps disambiguate some usage
+# scenarios. Here are some examples:
+#
+# "${x}" is the same as $x.
+# "${x}:" is the same as $x:.
+# "${x}${y}" is the same as $x$y.
+#
+# However, "${x}avier" is NOT the same as $xavier! Can you see why?
+#
+# You may use any variable names you like. There are no restrictions.
+# echo() uses no global variable names of its own, but receives the
+# string it interpolates in a string scanning environment.
+#
+############################################################################
+#
+# Using echo() on a larger scale , with input from a generator:
+#
+# global time, date, save, wombats
+#
+# link echo
+#
+# procedure main()
+# time := &clock
+# date := &date
+# save := ?100000
+# wombats := 22
+# "It is now $time on $date and you have savings of $$$save." |
+# "The number of wombats is $wombats." |
+# "It is now ${time} on ${date} and you have ${wombats} wombats." |
+# "There is no global variable named \"$foo\"." |
+# "This does not work: It is now ${&clock}." |
+# "" |
+# "The previous input line printed an empty output line." ? echo()
+# end
+#
+# Because echo() always fails (in the Icon sense), evaluation of
+#
+# a | b | c | d ? echo()
+#
+# will group as
+#
+# (a | b | c | d) ? echo()
+#
+# because of operator precedence, and the left-hand expression produces
+# _a_ first, which is assigned to &subject. Then echo() is evaluated --
+# and fails. This makes the whole expression fail, so Icon backtracks
+# to the first expression, resumes its evaluation to produce its second
+# value b, which is assigned to &subject and then echo() is called,
+# which fails, and so forth, until all possibilities are exhausted.
+#
+############################################################################
+#
+# Taking input from a template file:
+#
+# You can create a template file (with $-strings in it) and use an Icon
+# program to read it and write it out to standard output. Your main
+# Icon program will supply the needed variable values for the $-strings
+# in the template.
+#
+# As an example, suppose your program will generate a hundred business
+# cards for you as a PostScript file. You have a template file named
+# template.ps with $-strings such as $firstname, $lastname, $address,
+# $companyname, and so on --- all embedded in it at the proper places.
+# Your main program will read this template and substitute the actual
+# name and address information.
+#
+# This is one way your program can read template.ps and pass it to
+# echo():
+#
+# ...
+# firstname := "Joe"
+# lastname := "Smith"
+# # ... etc. ...
+# reads("template.ps",1000000) ? echo()
+# ...
+#
+# When this is run, your customized business cards appear on standard
+# output.
+#
+############################################################################
+#
+# This trick relies upon concatenation having a higher precedence
+# than alternation:
+#
+# "................" ||
+# "................" ||
+# "................" |
+# "................" ||
+# "................" |
+# "................" ||
+# "................" ? echo()
+#
+# This prints out three messages, one specified on three lines, one on
+# two, and one on two. The alternations fix the newlines provided at the
+# end of each message by echo().
+#
+# &subject is the empty string if it's unassigned. So echo() called
+# without ? will under those circumstances print a blank line.
+#
+############################################################################
+
+procedure echo() #: interpolate variables and print
+
+ $define idchars 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_'
+ while writes(tab(find("$")) ) do {
+ move(1)
+ writes( ="$" |
+ variable(tab(many(idchars)) |
+ 2( ="{", tab(find("}")), ="}" )
+ )
+ ) |
+ tab(many(idchars)) |
+ ( ="{" & tab(find("}")) & ="}" )
+ }
+ write(tab(0))
+ $undef idchars
+
+end