%==============================================================================%
%                                Start of Ch2.tex                              %
%==============================================================================%
%
% Copyright
% ---------
% Copyright (C) 1992 Ross N. Williams.
% This file contains a chapter of the FunnelWeb User's Manual.
% See the main TeX file for this manual for further information.
%
%==============================================================================%

\chapter{FunnelWeb Hints}
\label{chapadvanced}\xx{FunnelWeb}{hints}

Whereas Chapter~\ref{chapintroduction} provides an introduction to
FunnelWeb and Chapter~\ref{chapdefinition} a definition, \i{this} chapter
contains hints about how
FunnelWeb can be used. This chapter probably should not be read until
the reader has already commenced using FunnelWeb, or at the very least,
tried out some of the examples in Chapter~\ref{chapintroduction}.
Those who find themselves using FunnelWeb frequently
should read this chapter at some stage
so as to ensure that they are getting the most out of it.

Most of the examples in this chapter have been
placed in the FunnelWeb regression test suite which should be
available in a directory called \p{/fwdir/tests/}.
The files to examine are \p{hi01.fw} through \p{hi10.fw}.

\section{Macro Names}
\xx{macro}{names}\xx{macro}{identifiers}

When using FunnelWeb, the choice of macro names can be as
important to the readability of a program as the choice of program
identifiers,
and it is important that the user know the range of options available.

\narrowthing{Names are case sensitive and exact matching:}{Macro names are case
sensitive and are matched exactly. The strings used as a macro name
at the point of definition and call must be
\i{identical} for the connection to be made.}

\narrowthing{Names can contain any printable character:}{FunnelWeb is less
restrictive about its macro names than most programming languages are
about their identifiers. A FunnelWeb macro name can contain any
sequence of printable characters, including blanks and punctuation. Names
can start and end with any character. Names cannot cross line boundaries. The
following are all legal macro names:}

\begin{verbatim}
        @<This macro expands to some really bad code@>
        @<@>
        @<453 #$ %&# --===~~1">>>@>
        @<<@>
        @<<>@>
        @<a b c d e f g@>
        @<       !     @>
        @<?? ...@>
        @<"Who's been hacking MY program" said Father Bear.@>
        @<Update the maximum and return for more data@>
\end{verbatim}

\narrowthing{Names must be no more than a maximum limit in length:}{Names
can be
no longer than a predefined maximum length. Currently this length cannot
be modified.}

Typically, macro names will consist of a short English phrase or sentence
that describes the contents of the macro.

\section{Quick Names}
\xx{quick}{names}

Sometimes a particular macro must be used extremely often. When this happens
it is desirable to make the macro's name as short as possible.
The shortest ordinary FunnelWeb macro name is the empty name\xx{empty}{name}
\dqp{@<@>}, which is four characters long. Single-character names are
five characters long.

To cater for the cases where really short names are needed, FunnelWeb provides
a \newterm{quick name} syntax that allows one-character macro names to be
specified in two less characters. Quick names take the form of the special
character, followed by a hash (\p{\#}) followed by a single character.
Examples:

\begin{verbatim}
@#A     @#|     @#&     @#m
\end{verbatim}

This form of macro name has the same syntactic functionality as an ordinary
name and can be substituted wherever an ordinary name can be. In fact
quick names live in the same namespace as ordinary macro names. For example
the quickname \p{@\#A} is the \i{same name} (refers to the same macro)
as the ordinary name \p{@<A@>}.

Because quick names look syntactically \dq{open} (\ie{}they do not have
a closing\p{@>} as ordinary names do), it is best to avoid them except
where a macro must be called very often.

\section{FunnelWeb the Martinet}
\xx{FunnelWeb}{rules}\xx{FunnelWeb}{martinet}

There are many ways in which a macro preprocessor can cause unexpected
difficulties. FunnelWeb seeks to avoid many of these problems by performing
a number of checks. This section describes some of the checks that
FunnelWeb performs.

\narrowthing{Trailing blanks in the input file:}{Trailing
blanks\xx{trailing}{blanks} are usually
not dangerous, but
FunnelWeb disallows them anyway. All trailing blanks in the
\i{input} (\p{.fw} file) are flagged as errors by FunnelWeb.
FunnelWeb does not flag trailing blanks in any of its output files.}

\narrowthing{Input line length:}{FunnelWeb has a maximum input line
length.\xx{input line}{length}
If FunnelWeb reads an input line longer than this length, it flags the
line with an error message. The maximum length can be changed using a
pragma (see Chapter~\ref{chapdefinition}).}

\narrowthing{Product file line length:}{FunnelWeb
watches the length of output lines\xx{output line}{length}
and all output lines longer than the limit are flagged with error
messages.
The maximum length can be changed using a
pragma (see Chapter~\ref{chapdefinition}).
That FunnelWeb polices output lines is very important. Some programs
can behave very strangely if they get an input line that is too long
(\eg{}Fortran compilers\xx{Fortran}{compilers}
can simply ignore text past a certain column!)
and once FunnelWeb starts expanding macros using indentation, it is sometimes
not obvious how wide the product file will be.}

\narrowthing{Control characters:}{The presence of control
characters\xx{control}{characters} in a text file
can result in some confusing behaviour downstream when the file is
presented to various programs. Unfortunately, some text
editors\xx{text}{editors} allow
control characters to be inserted into the text rather too easily, and it is
all too easy to be tripped up. FunnelWeb prevents these problems by flagging
with diagnostics all non-end-of-line control characters detected
in the input (\p{.fw}) file (even TABs\x{tabs}).
The result is that the user is
guaranteed that product files generated from FunnelWeb contain no
unintentional control characters. This said, FunnelWeb does allow the
insertion of control characters in the output file by explicitly
specifying
them in the text using a \p{@\circumflex{}} control sequence.}

\narrowthing{Number of invocations:}{FunnelWeb
checks the number of times that\xx{invocations}{number}
each macro is called and issues an error if the total is not one. The
\p{@Z} (for zero) and \p{@M} (for many) macro attributes can be used
to bypass these checks.}

\narrowthing{Recursion:}{Because\xx{recursion}{macro}
FunnelWeb does not provide any conditional
constructs, all recursively defined macros must, by
definition, expand infinitely,\footnote{A special case exists where
there is recursion but no content. In this case, the expansion is finite
(the empty string) even though the operation of expanding is infinite.
FunnelWeb does not treat this case specially.} and are therefore
unacceptable. FunnelWeb performs \i{static} checks to detect recursion,
detecting it before macro expansion commences. The user need not fear that
FunnelWeb will lock up or spew forth
if a recursive macro is accidentally specified.}

\section{Fiddling With End of Lines}
\xx{EOL}{fiddling with}\xx{end-of-line}{fiddling with}\x{spacing}

One of the  fiddly aspects of programming  with FunnelWeb is coping  with end of
lines. If  you want  your product file to be  well indented without
multiple blank lines  or code run-ons,  you have to spend a  little time working
out how the end of line markers get moved around.

The rule  to remember is that,
disregarding the  effects of  special sequences
within a macro body, \i{the body of a macro consists of exactly the text
between the opening \p{@\{} and the  closing \p{@\}}}. This text includes end of
line markers.

If for example you call a macro in a sequence of code$\ldots$

\begin{verbatim}
while the_walrus_is_sleepy do
   begin
   writeln('zzzzzzz');
   @<Wake up the walrus@>
   writeln('Umpharumpha...');
   end;
\end{verbatim}

where \p{<wake up the walrus>} is defined as follows

\begin{verbatim}
@$@<Wake up the walrus@>==@{
wake_up_the_walrus(the_walrus);
@}
\end{verbatim}

then when \p{<Wake up the walrus>} is expanded you will get

\begin{verbatim}
while the_walrus_is_sleepy do
   begin
   writeln("zzzzzzz");

   wake_up_the_walrus(the_walrus);

   writeln("Umpharumpha...");
   end;
\end{verbatim}

The blank  lines were  introduced by  the end  on line  markers included  in the
definition of \p{<Wake  up the walrus>}. A  good solution to this  problem is to
suppress the end of line markers by defining the macro as follows

\begin{verbatim}
@$@<Wake up the walrus@>==@{@-
wake_up_the_walrus(the_walrus);@}
\end{verbatim}

This is the usual form of macro definitions in FunnelWeb files.

In additive macros, this format  does not
work properly because the end of line that is suppressed by the trailing \p{@\}}
does not get replaced by the end of line at the end of the macro invocation. For
example the definition

\begin{verbatim}
@$@<Wake up the walrus@>+=@{@-
wake_up_the_walrus_once(the_walrus);@}
\end{verbatim}

later followed by

\begin{verbatim}
@$@<Wake up the walrus@>+=@{@-
wake_up_the_walrus_again(the_walrus);@}
\end{verbatim}

is equivalent to the single definition

\begin{verbatim}
@$@<Wake up the walrus@>==@{@-
wake_up_the_walrus_once(the_walrus);wake_up_the_walrus_again(the_walrus);@}
\end{verbatim}

Putting the trailing \p{@\}}  on a new line at the end of  the macro (except for
the last definition part) solves the problem.

\begin{verbatim}
@$@<Wake up the walrus@>+=@{@-
wake_up_the_walrus_once(the_walrus);
@}
\end{verbatim}

later followed by

\begin{verbatim}
@$@<Wake up the walrus@>+=@{@-
wake_up_the_walrus_again(the_walrus);@}
\end{verbatim}

is equivalent to the single definition

\begin{verbatim}
@$@<Wake up the walrus@>==@{@-
wake_up_the_walrus_once(the_walrus);
wake_up_the_walrus_again(the_walrus);@}
\end{verbatim}

Managing end of line markers is tricky,
but once you establish  a convention for coping
with them, the problem disappears into the background.

\section{Fudging Conditionals}
\xx{fudging}{conditionals}

As a macro preprocessor, the facility that FunnelWeb most obviously lacks
is a conditional facility (such as C's \p{\#ifdef}). It might, therefore,
come as a surprise to know that the first version  of FunnelWeb
actually had a built in conditional facility. The facility allowed
the programmer to specify a construct that would select from one of a number
of macro expressions depending on the value of a controlling macro expression.

In three years the construct was never used.

The reason was that conditional constructs could be fudged nearly
as easily as they could be used. Because of this, the inbuilt conditional
feature was removed in the current version of FunnelWeb. Not only did this
simplify the program, but is also allowed recursive macros to be detected
through static analysis rather than during macro expansion.

There are two basic ways to fudge a conditional. First, the comment
facility of the target programming language may be employed. For example,
in Ada,\x{Ada}
comments commence with \dqp{--} and terminate at the end of the line.
Using this fact, it is easy to construct macros that can be called at the
start of each target line and which turn on and off the lines so
marked by defining the macro to be the empty string (ON) or the comment
symbol (\p{--}) (OFF). For example:

\begin{verbatim}
@A@<Debug Macro@>

The following macro determines whether debug code will be included in the
program. All lines of debug code commence with a call to this macro and so
we can turn all that code on or off here by defining this macro to be either
empty or the single-line comment symbol (\p{--}). Note the use of a
quick macro name.

@$@#D@M==@{@}     @! Turns the debug code ON.
@! Use this definition to turn the debug code OFF: @$@#D==@{--@}

... then later in the file...

@$@<Sloth incrementing loop@>==@{@-
while sloth<walrus loop
   @#D assert(sloth<walrus,"AWK! sloth>=walrus!!!!!!!");
   @#D assert(timer<timermax,"AWK! timer>=timermax!!!");
   inc(sloth);
end loop@}
\end{verbatim}

The other way to fudge a conditional is to define a macro with a
single parameter. A call to the macro is then wrapped around all the
conditional code in the program. The macro can then be defined to
present or ignore the code of its argument. For example:

\begin{verbatim}
@A@<Debug Macro@>

The following macro determines whether debug code will be included in the
program. All debug code is wrapped by a call to this macro and so
we can turn all the debug code on or off here by defining this macro to be
either empty or its parameter.

@$@#D@(@1@)@M==@{@1@}     @! Turns the debug code ON.
@! Use this definition to turn the debug code OFF: @$@#D@(@1@)==@{@}

... then later in the file...

@$@<Sloth incrementing loop@>==@{@-
while sloth<walrus loop
   @#D@(assert(sloth<walrus,"AWK! sloth>=walrus!!!!!!!");
        assert(timer<timermax,"AWK! timer>=timermax!!!");@)
   inc(sloth);
end loop@}
\end{verbatim}

In languages that allow multi-line comments (\eg{}C with \p{/*} and \p{*/}),
comments can be used to eliminate the conditioned code rather than
absence.  For example:

\begin{verbatim}
@$@#D@(@1@)@M==@{/* @1 */@}    @! Comments out the debug code
\end{verbatim}

(Note: If this example were ever actually used,
the programmer would have to be careful not to place comments in
the argument code. Nested comments in~C are non-portable.)

The parameterized macro idea can be generalized to support the choice of
more than one mutually exclusive alternative. For example:

\begin{verbatim}
@A This module contains non-portable code that must execute on Hewlett
Packard, Sun, and DEC workstations. The following FunnelWeb macro is
defined to choose between these three. The first parameter is the HP code,
the second is the Sun code, and the third is the DEC code. Whichever
parameter constitutes the body of this macro determines which
machine the code is being targeted\note{Dictionary says only one t
in targeted.} for.

@$@<Machine specific code@>@(@3@)@M==@{@1@}  @! Configure for HP.

...then later in the file...

@<Machine specific code@>@(
@"get_command_line(comline)@"           @, @! HP.
@"scan_command_line(128,comline);@"     @, @! Sun.
@"dcl_get_command_line(comline,256);@"  @) @! DEC.
\end{verbatim}

Of course, this could also be performed using three separate macros. The
main advantage of using a single macro is that the mutual exclusivity is
enforced. Also, because FunnelWeb ensures that the number of formal and
actual parameters are the same, this method lessens the chance that a
machine will be forgotten in some places.


\section{Changing the Strength of Headings}
\xx{headings}{strength}\xx{typesetting}{strength}%
\xx{section}{strength}\xx{font}{size}

FunnelWeb provides five heading levels:
\p{@A}, \p{@B}, \p{@C}, \p{@D}, and \p{@E} to which it binds five different
typographical strengths. These bindings are static; a level
\p{@A} heading will always be typeset in a particular font size regardless
of the size of the document. The font
sizes have been preset to be \dq{reasonable} for a range of document sizes,
but may be inappropriate for very small or large documents.

FunnelWeb does not currently provide an \dq{official}
way (\eg{}a pragma) to change the typesetting
strength of headings. This feature might be added in later versions.
Meanwhile, a hack is available that will do the job, providing that you
do not mind the hack being \TeX{}-specific and probably FunnelWeb-version
specific.

Inside the set of \TeX{} macro definitions
that FunnelWeb writes at the top of every documentation
file are five \dq{library}
definitions \p{fwliba}$\ldots$\p{fwlibe} which
provide five different typesetting strengths for headings. Near the
end of the set of definitions, FunnelWeb binds these macros to five
other macros \p{fwseca}$\ldots$\p{fwsece} which are invoked directly in the
generated \TeX{} code to typeset the headings.

\begin{verbatim}
\def\fwseca#1#2{\fwliba{#1}{#2}}
\def\fwsecb#1#2{\fwlibb{#1}{#2}}
\def\fwsecc#1#2{\fwlibc{#1}{#2}}
\def\fwsecd#1#2{\fwlibd{#1}{#2}}
\def\fwsece#1#2{\fwlibe{#1}{#2}}
\end{verbatim}

This means that the typesetting strength of the headings in a FunnelWeb
document can be changed by redefining these macros at the top of a FunnelWeb
document. For example:

\begin{verbatim}
@p typesetter = tex
\def\fwseca#1#2{\fwlibc{#1}{#2}}
\end{verbatim}

would set \p{@A} headings at the same strength as the default strength of
\p{@C} headings. The \p{typesetter} directive is necessary to ensure that the
\TeX{} control sequences get through to the documentation file unfiltered.

The following will tone down all headings by two levels (with the
\p{@D} and \p{@E} levels being allocated the default \p{@E} typesetting
strength because there is nothing weaker).

\begin{verbatim}
@p typesetter = tex
\def\fwseca#1#2{\fwlibc{#1}{#2}}
\def\fwsecb#1#2{\fwlibd{#1}{#2}}
\def\fwsecc#1#2{\fwlibe{#1}{#2}}
\def\fwsecd#1#2{\fwlibe{#1}{#2}}
\def\fwsece#1#2{\fwlibe{#1}{#2}}
\end{verbatim}

These definitions affect only the headings that follow them, and so they
should be placed at the top of the FunnelWeb input file.

\section{Efficiency Notes}
\xx{FunnelWeb}{efficiency}\xx{efficiency}{notes}

The following notes are worth keeping in mind when using FunnelWeb.

\narrowthing{Memory:}{When\x{memory}\xx{input}{files}
FunnelWeb processes an input file, it reads
the entire input file, and all the included files into memory.\footnote{If a
file is included $n$ times, FunnelWeb keeps $n$ copies in memory.} This
organization does not pose a constraint on machines with large memories,
but could
present a problem on the smaller machines such as the PC.}

\narrowthing{Speed:}{FunnelWeb\x{speed} is not a slow program. However, it is
not particularly fast either. If the speed at which FunnelWeb runs is
important to you, then the thing to keep in mind is that FunnelWeb has been
optimized to deal efficiently with large slabs of text. FunnelWeb treats
input files as a sequence of text slabs and special sequences (\eg{}\p{@+})
and whenever it hits a special sequence, it has to stop and think.
Thus, while a ten megabyte text slab would be manipulated as a single token,
in a few milliseconds, a similar ten megabyte chunk filled with special
sequences would take a lot longer.
If FunnelWeb is running slowly, look to see if the input contains
a high density of special sequences. This can sometimes happen if FunnelWeb
is being used as a backend macro processor and its input is being
generated automatically by some other program.}

\narrowthing{Macro expansion:}{When\xx{macro}{expansion}
tangling (expanding macros), FunnelWeb never
expands a macro expression into memory; it always writes it to the
product file
as it goes. This is a powerful fact, because it means that you can
write macros containing an unlimited amount of text, and pass such macros
as parameters to other macros without becoming concerned about overflowing
some kind of buffer memory. In short, FunnelWeb does not impose any
limits on the size of macro bodies or their expansions.}

\section{Interactive Mode}
\x{interactive mode}\x{keyboard mode}

As well as having a command line interface with lots of options, FunnelWeb
also provides a command language and a mode (\dq{interactive mode})
in which commands in the language can be typed interactively. The
FunnelWeb command interpreter was created primarily
to support regression testing,\xx{regression}{testing}
but can also be useful to FunnelWeb users.

FunnelWeb's command interpreter\xx{command}{interpreter}
reads one command per line and can read
a stream of commands either from a text file, or from the console. The
interpreter can understand over twenty commands. See
Chapter~\ref{chapdefinition} for a full list. However, most of them
were designed to support regression testing and will not be of use to the
casual user.

The commands that are of greatest use to the casual user
are:\xx{useful}{commands}

\begin{verbatim}
     !               - Comment. Ignores the whole line.
     EXECUTE fn      - Execute the specified file.
     FW options      - Invoke FunnelWeb-proper once.
     SET options     - Sets options.
     SHOW            - Displays currently active options.
     TRACE ON        - Turns command tracing ON.
     QUIT            - Quits FunnelWeb.
\end{verbatim}

To distinguish here between invocations of the FunnelWeb program
and FunnelWeb runs inside the shell, we call the latter \newterm{FunnelWeb
proper}. The \dqp{FW} command invokes FunnelWeb proper with the specified
options which take the same syntax as they do on the command line. The only
restriction is that none of the action options can be turned on except
\dqp{+F} which must be turned on.

The \dqp{SET} command\xx{set}{command}
has the same syntax as the \dqp{FW} command except that it
does not allow \i{any} action options to be
specified. It's sole effect is to set default option values for the
rest of the run.

The \dqp{SHOW}\xx{show}{command}
command displays the current default options.

By default, FunnelWeb does not echo the commands that it processes in a
script. The \dqp{TRACE ON}\xx{trace on}{command}
command turns on such tracing.

These commands can be combined to streamline the use of FunnelWeb.
For example, you might wish to create a script called \p{typeset.fws}
to process a whole group of files.

\begin{verbatim}
trace on
!This script typesets the whole program.
! Set no listing file, no product files, but specify a documentation file
! and specify the directory into which it should be placed.
set -L -O +T/usr/ross/typeset/
fw prog1
fw prog2
fw prog3
fw prog4
\end{verbatim}

There are a few ways in which this script can be run. The simplest is
simply to specify it in the \dqp{+X} option of a FunnelWeb invocation.
FunnelWeb shellscripts default to \dqp{<current\_directory>} and \dqp{.fws}.

\begin{verbatim}
fw +xtypeset
\end{verbatim}

The second alternative is to enter interactive mode.

\begin{verbatim}
fw +k
\end{verbatim}

From there, you can execute the script using:

\begin{verbatim}
execute typeset
\end{verbatim}

Interactive mode could be very useful to those with multiple-window
workstations.\x{workstations}
The user could create a window containing an interactive
session of FunnelWeb, and then switch between windows, editing, and executing
FunnelWeb proper and other programs.

If you find yourself using the command interpreter a lot, be sure to
read about the other commands that are available in
Chapter~\ref{chapdefinition}.

\section{Setting Up Default Options}
\xx{options}{setting defaults}\xx{default}{options}

If you do not like FunnelWeb's default settings for its command line
options, there are a number of ways in which you can change them.

\narrowthing{Define an \dq{alias}:}{Use your operating system
\dqp{alias}\x{alias}
facility to create an alias for FunnelWeb containing the desired options.
FunnelWeb processes options from left to right, so you can override
these defaults later if you wish.}

\narrowthing{Create a script called \dqp{fwinit.fws}:}{When FunnelWeb
starts up, it executes a script called \dqp{fwinit.fws}\x{fwinit.fws}
if\xx{startup}{script}\xx{initialization}{script} such a
script exists in the current directory. You can use this fact to set options
before the run of FunnelWeb proper by creating such a script and placing
a single \dqp{set} command in it containing the desired options. The main
trouble with this approach is that the options in the \p{set} command will
be processed \i{after} the command line options, which means that you won't
be able to override them on the command line.}

For example, you might be involved more with presenting programs than with
running them, and want FunnelWeb to generate a documentation
file by default, but not to produce
listing or product files by default. In Unix you could do this with:

\begin{verbatim}
alias fw fw -L -O +T
\end{verbatim}

\section{FunnelWeb and Make}
\x{make utility}\xx{file}{dependencies}

The Unix \p{Make} program allows a set of dependencies between a set of
files to be described, and then uses these dependencies to control the way in
which the files are created and updated. Typically,
\p{Make} is used to control the process of transforming a collection of
source code files to one or more executable files.
As the use of FunnelWeb implies an extra stage to this process, it is
natural to include the transformation of \p{.fw} files to source code
files as part of the \p{Make} process. This is easy to do, but the user
should be aware of one aspect of FunnelWeb which can cause problems.

It is often useful, when using FunnelWeb, to create a FunnelWeb \p{.fw}
file that generates more than one product file.
That is, a single \p{.fw} file may have many macro definitions connected
to product files so that when the FunnelWeb \p{.fw} file is processed by
FunnelWeb, several files are created. For example, this facility has been
used to great effect to place the description of an Ada\x{Ada} package's
package specification file and package body file in the same FunnelWeb
\p{.fw} file.

The use of multiple product files, however, provokes a problem
with dependencies. Suppose for example that a FunnelWeb \p{prog.fw}
produces two product files \p{proc.spec} (a package specification)
and \p{prog.body} (a package body). If the package is accessed in the way
that packages normally are, it will be quite common for the programmer
to want to modify the package body without modifying the program specification.
So the programmer will edit the \p{prog.fw} file to change the package
body. The result of running this through FunnelWeb will be the desired
new package body file. However, FunnelWeb will also produce a new package
specification product file \i{even though it may be identical to the
previous version!} The result is that the newly created (with a recent
file date) specification package file could provoke a huge remake of much
of the program in which it resides.

To solve the problem, FunnelWeb includes a command line option 
(\p{D} for Delete),\xx{D}{option}\xx{delete}{output files}
which when turned on (using \dqp{+D}) causes
FunnelWeb to suppress\xx{suppression}{file}
product and documentation files that are identical
to the previously existing versions of the same files. For example,
if, during a FunnelWeb  run, a macro was connected to a product file called
\p{x.dat}, and the macro expanded to \i{exactly} the same text as is
contained in \p{x.dat} then FunnelWeb would simply \i{never write the product
file}, the file \p{x.dat} would be untouched and, as a result, no further
\p{Make} propagations would take place.

FunnelWeb implements this feature by writing each product file to
a temporary file with a temporary file name. It then compares the temporary
file with the target file. If the two are identical, it deletes the
temporary file. If the two are different it deletes the target file and
renames the temporary file to the target file.

Use of the \p{D} facility means that the programmer need not be punished
(by extra \p{Make} propagations) for describing more than one product file
in the same FunnelWeb file.


\section{The Dangers of FunnelWeb}
\xx{FunnelWeb}{dangers}\xx{FunnelWeb}{pitfalls}

Like many tools that are general and flexible, FunnelWeb can be used in a
variety of ways, both good and bad. One of the original appeals of the
literate approach to programming for Knuth,\xn{Donald}{Knuth}
the inventor of literate
programming,\xx{literate}{programming}
was that it allows the programmer to describe the target
program bottom up, top down, size to side, or chaotically if desired.
The flexibility that this style of programming leaves much
room for bad documentation as well as good documentation. Years of
experience with FunnelWeb has revealed the following stylistic pitfalls
which the experienced FunnelWeb user should take care to
avoid.\footnote{The fact that these faults are listed here does not mean
that the author has eliminated them in his own work. Rather,
it is mainly the author's own mistakes that have resulted in this list
being compiled. The author immediately
confesses to several of the faults listed here, most notably that of
Pavlov documentation.}

\narrowthing{Spaghetti organization:}{By\xx{spaghetti}{organization}
far the worst problem that arises
in connection with the literate style occurs where the programmer has
used the literate tool to completely scramble the program so that the
program is described and layed out in an unordered, undisciplined
\dq{stream of consciousness}.\x{stream of consciousness}
In such cases the programmer may be using
the literate style as a crutch to avoid having to
think about structuring the presentation.}

\narrowthing{Boring organization:}{At\xx{boring}{organization}
the other extreme, a program may be
organized in such a strict way that it is essentially laid out in the
order most \dq{desired} by the target programming language. For example,
each macro might contain a single procedure, with all the macros being
called by a macro connected to a file at the top. In many cases a boring
structure may be entirely appropriate, but the programmer should be warned
that it is easy to slip into such a normative style, largely forgetting the
descriptive structural power that FunnelWeb provides.}

\narrowthing{Poor random access:}{Using\xx{random}{access}
FunnelWeb, it is quite possible to write
programs like novels\x{novels}
--- to be read from cover to cover. Sometimes the
story is very exciting, with data structures making dashing triumphs and
optimized code bringing the story to a satisfying conclusion. These programs
can be works of art.
Unfortunately, without careful construction,
such \dq{novel-programs} can become very hard to access randomly by (say)
a maintenance programmer\xx{maintenance}{programmer}
who wishes only to dive in and fix a specific
problem. If the entire program is scrambled for sequential exposition, it
can be hard to find the parts relating to a single function.
Somehow a balance must be struck in the document between the
needs of the sequential and of the random-access reader.
This balance will depend on the intended use of the program.}

\narrowthing{Too-interdependent documentation:}{Sometimes,
when\xx{documentation}{interdependent} editing a 
program written using FunnelWeb, one knows how to modify the program,
but one is unsure of how to update the surrounding documentation!
The documentation may be woven into such a network of facts that it seems that
changing a small piece of code could invalidate many
pieces of documentation scattered throughout the document. The documentation
becomes a big tar pit in which movement is impossible.
For example,
if you have talked about a particular data structure invariant throughout
a document, changing that invariant in
a small way could mean having to update all the documentation without
touching much
code. In such cases, the documentation is too interdependent. This could be
symptomatic of an excessibly interconnected program, or of an
excessively verbose or redundant documenting style. In any case, a balance
must be struck between the conversational style that encourages redundancy
(by mentioning things many times) and the normalized database approach where
each fact is given at only one point, and the reader is left to figure
out the implications throughout the document.}

\narrowthing{Pavlov documentation:}{By\xx{pavlov}{documentation}
placing so much emphasis on the documentation,
FunnelWeb naturally provides slots where documentation \dq{should} go. For
example, a FunnelWeb user may feel that there may be a rather unpleasant
gap between a \p{@C} marker and the following macro. In many cases \i{no}
commentary is needed and the zone is better left blank rather than being
filled with the kind of uninformative waffle one often finds filling the slots
of structured documentation written according to a military standards
(\eg{}MIL-STD-2167A).\x{MIL-STD-2167A}\x{2167A}\footnote{Note:
This is not a criticism of 2167A,
only of the way it is sometimes used.} The lesson is to add documentation
only when it adds something. The lesson in Strunk and White\paper{Strunk79}
(p.~23)
holds for
program documentation as it does for other writing: \dq{Vigorous writing is
concise. A sentence should contain no unnecessary words, a paragraph no
unnecessary sentences, for the same reason that a drawing should have
no unnecessary lines and a machine no unnecessary parts. This
requires not that the writer make all his sentences short, or that he avoid
all detail and treat his subjects only in outline, but that every word
tell.}.\checked{}}

\narrowthing{Duplicate documentation:}{Where\xx{duplicate}{documentation}
the programmer is generating
product files that must exist on their own within the entire programming
environment (\eg{}the case of a programmer in a team who is using FunnelWeb
for his own benefit but must generate (say) commented Ada\x{Ada}
specification
package files) there is a tendency for the comments in the
target code to duplicate the commentary in the FunnelWeb text. This may or
may not be a problem, depending on the exact situation. However, if this is
happening, it is certainly worth the programmer spending some time deciding
if one or other of the FunnelWeb or inline-comment documentation should be
discarded.
In many cases, a mixture can be used, with the FunnelWeb documentation
referring the reader to the inline comments where they are present.
For example:}

\begin{verbatim}
@A Here is the header comment for the list package specification.
The reader should read these comments carefully as they define a list.
There is no need to duplicate the comments in this text.

@$@<Specification package header comments@>==@{@-
-- LIST PACKAGE
-- ============
-- * A LIST consists of zero or more ITEMS.
-- * The items are numbered 1 to N where N is the number of items in the list.
-- * If the list is non-empty, item 1 is called the HEAD of the list.
-- * If the list is non-empty, item N is called the TAIL of the list.
-- ...
@}
\end{verbatim}

\narrowthing{Overdocumenting:}{Another\xx{over}{documentation}
evil that can arise when using FunnelWeb is
to over-document the target program. In some of Knuth's earlier (\eg{}1984)
examples of literate programming, each variable is given its own description
and each piece of code has a detailed explanation. This level of analysis,
while justified for tricky tracts of code, is probably not warranted
for most of the code that constitutes most programs. Such over-commenting
can even have the detrimental affect of obscuring the code, making it hard
to understand because it is so scattered (see \dq{spaghetti organization}
earlier). It is up to the user to decide when a stretch of just a few lines of
code should be pulled to bits and analysed and when it is clearer to leave it
alone.}

\narrowtext{In the case where there
are a few rather tricky lines of code, a detailed
explanation may be appropriate. The following example
contains a solution to a problem outlined in section 16.3 of
the book \dq{The Science of Programming} by David Gries\paper{Gries81}.}

\begin{verbatim}
@C@<Calculation of the longest plateau in array b@>

This section contains a solution to a problem outlined in section 16.3 of
the book @/The Science of Programming@/ by David Gries[Gries81].

@D Given a sorted array @{b[1..N]@} of integers, we wish to determine the
@/length@/ of the longest run of identically valued elements in the array.
This problem is defined by the following precondition and postcondition.

@$@<Precondition@>==@{/* Pre: sorted(b). */@}
@$@<Postcondition@>==@{@-
/* Post: sorted(b) and p is the length of the longest run in b[1..N]. */@}

@D We approach a solution to the problem by deciding to try the approach of
scanning through the array one element at a time maintaining a useful
invariant through each iteration. A loop variable
array index @{i@} is created for this purpose. The bound function is
@{N-i@}. Here is the invariant.

@$@<Invariant@>==@{@-
/* Invariant: sorted(b) and 1<=i<=N and           */
/*            p is len of longest run in b[1..i]. */@}

@D Establishing the invariant above in the initial, degenerate case is easy.

@$@<Establish the plateau loop invariant initially@>==@{i=1; p=1;@}

@D At this stage, we have the following loop structure. Note that when both
the invariant and @{i != N@} are true, the postcondition holds and the loop
can terminate.

@$@<Set p to the length of the longest plateau in sorted array b[1..N]@>==@{@-
@<Precondition@>
@<Establish the plateau loop invariant initially@>
while (i != N)
  {
   @<Invariant@>
   @<Loop body@>
  }
@<Postcondition@>
@}

@D Now there remains only the loop body whose sole task is to increase @{i@}
(and so decrease the value of the bound function) while maintaining the
invariant. If @{p@} is the length of the longest run
seen so far (i.e. in b[1..i]), then, because the array is sorted,
the extension of our array range to
@{b[1..i+1]@} can only result in an increase in @{p@} if the new element
terminates a run of length @{p+1@}. The increase can be at most 1. Because
the array is sorted, we need
only compare the endpoints of this possible run to see if it exists. This
is performed as shown below.

@$@<Loop body@>==@{i++; if (b[i] != b[i-p]) p++;@}
\end{verbatim}

\narrowtext{Where the code is more obvious,
it is often better to let the code speak for itself.}

\begin{verbatim}
@C The following function compares two C~strings and returns TRUE iff they
are identical.

@$@<Function comp@>==@{@-
bool comp(p,q)
char *p,*q;
{
 while (TRUE)
   {
    if (*p != *q  ) return FALSE;
    if (*p == '\0') return TRUE;
    p++; q++;
   }
}
@}
\end{verbatim}

\section{Wholistic Debugging}
\xx{wholistic}{debugging}

Surprising though it may be, FunnelWeb has a key role to play in the
\i{debugging} of programs. Long experience in programming has led me to the
concept of \newterm{wholistic debugging}. When most programmers detect a
bug, their first reaction seems to be to jump into the debugger\x{debugger}
where they
often spend many hours stepping through endless stretches of code and 
generally wasting a lot of time.

In contrast, my first reaction when I detect a bug is to realize that
\i{the code must not be in good enough shape if such a bug can arise.}
The presence of the bug is taken as symptomatic of the lack of general
health of the code. If that bug occurred, why not another?
In response to this realization, my reaction is not to enter the debugger,
but rather to return to the original code and tend it like a
garden,\xx{code}{gardening}
adding more comments, reworking the grotty bits, adding assertions,
and looking for faults. In many cases, the search for faults does not
even centre on the specific bug that arose, but does tend to focus on
the area of code where the bug is likely to be.

The result is often that the original bug is located more quickly than it
would have been had the debugger been involved. But even if it isn't, there
are other benefits. A programmer who enters the debugger may
stay there for hours and still not find the bug. The result is
frustration and no positive gain at all. In contrast, by tending to the
code, the programmer is making forward progress at all times (the code
is constantly improving) even if the bug is not immediately found.
At the end of ten hours, the programmer can at least feel that the code
is \dq{ten hours better}, whereas the debugger freak will likely feel
defeated.
All this makes code tending better psychologically as well as a more
efficient approach to debugging.

I call this technique wholistic debugging, for it is like the
difference between conventional and wholistic medicine.\xx{wholistic}{medicine}
Go to a
conventional doctor with a headache and he might send off for head X-rays,
perform allergy tests and perform many other
debugging activities. Go to a wholistic doctor with the same problem and
he might look to see if you are fit, assess your mental health, and ask you
if your marriage is working. Both approaches are appropriate at different
times. In programming, the wholistic approach is not used enough.

\section{Examples of FunnelWeb Applications}
\xx{FunnelWeb}{example applications}\xx{FunnelWeb}{applications}

Despite (or perhaps because of) its flexibility and simplicity,
FunnelWeb can be applied to quite a number of different
text processing and documenting problems. This section describes some of
the more interesting real problems that FunnelWeb has solved.

\subsection{Analyzing the Monster Postscript Header File}
\xx{monster file}{postscript}

During my Ph.D. candidature, I determined at one point that it would be
very desirable to automatically insert diagrams from the \i{MacDraw}\x{MacDraw}
program on my Macintosh into
\TeX{}\x{TeX}
\p{insert}ions in my thesis.\xx{PhD}{thesis} This would allow diagrams to float
around with the text and be printed automatically rather than having to be
printed separately and stuck in with real glue. On the face of it, the
problem seemed inherently solvable as the Macintosh\x{Macintosh}
could generate PostScript\x{PostScript}
for each diagram and this PostScript could presumably be inserted into the
PostScript generated using \TeX{}.

The only trouble was that the Macintosh PostScript code for the diagrams
relied on an Apple PostScript header file.\xx{postscript}{header file}
This meant that the header file
had to be included at the start of the \TeX{} PostScript if the inserted
PostScript for the diagrams was to work.
Unfortunately, merely including the header file at the top didn't work, and
it turned out that a rather detailed analysis of some parts of the Apple
header file was required in order to perform the necessary surgery on the
header file to make it work. This analysis was severely aggravated by the
fact that the PostScript header file was virtually unreadable. Basically
it was about 50K of interwoven
definitions, that looked as if it had been run through a word processor.
There was no way that the code could be understood clearly without some
kind of reformatting. Two other aspects of the problem further complicated
the analysis:

\begin{itemize}

\item The definitions of interest (\ie{}the ones causing the problems)
were scattered throughout the file.

\item Many definitions could not be moved. For one or more reasons
(\eg{}to keep a definition within the activation of a particular
dictionary \p{begin} and \p{end}) it would have been unwise to move the
definitions of interest to the same point in the file.

\end{itemize}

In fact the file was so messy and complicated that, as a rule, it had to
be handled with kid gloves. It would have been unwise to re-arrange
the definitions or to insert comments.

To my surprise, FunnelWeb provided an unexpected solution to
the problem. First I replaced all occurrences of the \p{@} in the
header file with \p{@@}. Second, I placed the entire header file
in a FunnelWeb macro definition connected to a product file. I then
processed the file and checked to make sure that the product file
was identical to the original file.
By doing all this I had placed the
header file under FunnelWeb control. I then left the
macro definition largely untouched, but replaced the PostScript
definitions of
interest with FunnelWeb macro calls, moving the actual PostScript
definitions into FunnelWeb macro definitions at the end of the FunnelWeb
file.

\begin{verbatim}
@O@<LaserHeader.ps@>==@{@-
Unreadable Postscript code
@<Print routine@>
Unreadable Postscript code
@<Zap routine@>
Unreadable Postscript code
@}

@A This routine looks as if it does this, but really is does that,
blah, blah blah.

@$@<Print routine@>==@{@-
/print { push pop pop push turn around and jump up and down and print it} def
@}

@A This routine zaps the...

@$@<Zap routine@>==@{@-
/zap { push pop pop push turn around and jump up and down and print it} def
@}
\end{verbatim}

Use of FunnelWeb meant that I was able to pluck out the definitions of interest
(a very small part of the whole file) and collect them as a group at the end
of the file where they could be studied.
Because each definition was safely contained in a macro, it was possible to
write a detailed commentary of each routine without fear of affecting the
final PostScript code in any way at all. Once this analysis was completed,
it was possible to perform surgery on the offending PostScript definitions
in an extremely controlled way. In particular, the FunnelWeb input file
served as a repository for all the different versions of particular routines
that were tried in order to get the definitions to work. A new (\b{Z}ero)
macro was created for each version of each definition, and a commentary of how
it performed added above it.

This case demonstrates that
FunnelWeb is an extremely powerful tool for dissecting and
documenting cryptic text files.\xx{cryptic}{text files}
Through the use of macros, particular
parts of the file can be isolated and discussed without affecting the
final product file in any way. In the example above, only a small part of the
file was analysed, the rest being left as a blob, but in the general case,
a cryptic text file could be inserted into FunnelWeb and then incrementally
dissected (and possibly modified) until the result is a fully documented
literate program. That this can be done without affecting the actual
product file demonstrates the high degree of descriptive control that
FunnelWeb provides.

\subsection{Making Ada ADTs more A}
\x{Ada}\x{abstract data type}\x{ADT}

Like many modern programming languages, Ada provides mechanisms for hiding
information and structure. In particular, Ada provides a \newterm{package}
facility that allows the programmer to declare objects in a
package definition and define them in a corresponding package body.
This works well
for functions and procedures. However, in the case of types, implementation
issues (in particular, the need to know the size of exported types) have
led the designers of Ada to force the placement of
private type definitions in the definition package rather than the
implementation package. This means that some implementation details
are present in the package definition for all to see. While not actually
dangerous (the user of the package cannot make use of the information
without recourse to \dq{Chapter~13} of the Ada Language Reference
Manual\paper{DOD83}), this aspect of Ada is certainly unpleasant.

During the development of some Ada programs, FunnelWeb was used to solve
this problem. Instead of creating a separate file for the package
specification and package body, a single FunnelWeb file was created containing
two sections, one for the each package part. The \dq{private} part of the
package specification was then moved (using a FunnelWeb macro definition)
to the section describing the package body. Readers who wished only to read
the package specification could read only the first part, which contained
a fully documented description not containing the private definition.

\subsection{Multiple Language Systems}
\xx{multiple}{languages}

With the prevalence of open systems\x{open systems}
and multi-vendor computing, it is
often necessary to construct systems consisting of programs written in
a number of different programming languages for a number of different
systems. For example, a particular functionality might be implemented by a
shellscript
(invoked by the user) that calls a C~program that makes a network connection
to a Pascal program that queries a database. Quite often all these programs
must conspire closely to execute their function. In the normal case, they
must be written separately. FunnelWeb allows them to be written as a
whole.

By creating a single FunnelWeb file that creates many product files in
different languages, the programmer can describe the interaction between
the different programs in any manner desired. Furthermore, because
the different product files  are all created in the same \dq{text space}
(\ie{}in a single FunnelWeb file), it is easy for them to share information.

For example, in one real application FunnelWeb was used to create a
system for printing files\xx{printing}{system}
on a laser printer\xx{laser}{printer}
connected to a remote Vax
Unix machine from a local Vax VMS
machine. The system consisted of two files: a VMS DCL command procedure
to run on the local node, and a Unix shellscript to run on the remote
node. The user, by giving the print command, invoked the local VMS
command procedure, which in turn fired up the remote Unix shellscript. The
two scripts then cooperated to transfer the files to be printed and print
them.

In addition to its usual documentation powers, FunnelWeb assisted in the
creation of this system in two special ways. First, it allowed pieces of
code from the two different command procedures to be partially interwoven in a
description of their interaction. This is just not possible with comments.
Second, it facilitated the use of shared information. For example, under
some conditions, each file to be printed would be renamed and copied to the
remote system using a particular constant filename (\eg{}\dqp{printfile.tmp}).
FunnelWeb allowed this constant filename to be included in a single macro
definition which was invoked in the definition of each of the scripts. This
ensured that the two scripts used the same name.

\begin{verbatim}
@A The following macro contains the temporary file name used to allow the
two shellscripts to transfer each file to be printed.

@$@<printfile@>@M==@{printme.txt@}

@A Here are the scripts for the local VMS node and the remote UNIX node.

@O@<vmscommandprocedure.com@>==@{@-
DCL commands
copy @<printfile@> unixnode::
DCL commands
@}

@O@<unixshellscript@>==@{@-
unix commands
print @<printfile@>
unix commands
@}
\end{verbatim}

In the case of the printing system, the entire system was described and
defined in a single FunnelWeb \p{.fw} file. In larger systems containing
many FunnelWeb \p{.fw} files for many different modules in many different
languages, the same trick can be pulled by placing FunnelWeb macro
definitions for shared values into FunnelWeb include files. For example,
a suite of implementations of network nodes, with each implementation being
in a different programming language for a different target machine, could
all share a table of configuration constants defined in macros in a
FunnelWeb include file.

In summary, FunnelWeb's macro and include file mechanisms provide
a simple way for programs written in different languages to share
information. This reduces redundancy between the systems and hence the
chance of inconsistencies arising.\x{sharing information}

\subsection{The Case of the Small Function}
\xx{small}{functions}

Often, when programming, there is a need for a
code abstraction\xx{code}{abstraction} facility
that operates at the text level. If the statement \dqp{a:=3;} occurs often,
it may be best simply to repeat it verbatim. If a sequence of one hundred
statements is repeated often, it is normal to remove the code to a function
and replace the occurrences by a function call.
However, in between these two extremes are cases where a particular sequence
of code is long enough and appears often enough to be troublesome, but which
is bound so messily to its environment as to make a function call
cumbersome.

For example, the following line of statements (referring to five variables
declared \i{local} to a function) might appear ten times in
a function:

\begin{verbatim}
a=b*3.14159; c=d % 256; e=e+1;
\end{verbatim}

Now the \dq{normal} rule of programming says that these statements should be
placed in a procedure (also called a \dq{function} in the C programming language
used in this example),
but here five local variables are used. Use of a procedure
(function) would result in a procedure definition looking something like:

\begin{verbatim}
void frobit(a,b,c,d,e)
float *a,b;
int *c,d;
unsigned *e;
{*a=b << 8; *c=d % 256; *e=*e+1;}
\end{verbatim}

and a procedure call something like

\begin{verbatim}
frobit(&a,b,&c,d,&e);
\end{verbatim}

This might be workable in a language that allowed formal parameters to be
specified to be bound only to particular variables. Similarly, it might
be possible to avoid the parameter list in languages that support
local procedures that can access non-local variables (such as
Pascal\x{Pascal}).
However, in our example here, in the C programming language, these options
are not available, and so we must either create a function with five
parameters,
or use the C macro preprocessor\xx{preprocessor}{C}
(the best solution). FunnelWeb provides the
same macro facility for languages that do not have a built-in
preprocessor.

In particularly speed-stressed applications, the programmer may be
reluctant to remove code to a procedure because of the procedure-call
overhead.\xx{procedure call}{overhead}
FunnelWeb macros can help there too.

In summary, there sometimes arises in programming situations where the
cost of defining a procedure is higher than the benefits it will bestow.
Common reasons for this are the run-time procedure overhead and
the messy binding problems\xx{binding}{problems}
caused by removing target code from its target context. FunnelWeb
can help in these situations by allowing the programmer to define a text
macro. This avoids all the problems and provides an additional incentive
for the programmer to describe the piece of code so isolated.

\subsection{When Comments are Bad}
\xx{comments}{abuse}\xx{eliminating}{comments}

In the \dq{good old days}\x{good old days}
of small machine memories and interpreted BASIC,\x{BASIC}
programmers would eliminate the \dqp{REM} statements\xx{REM}{statement}
(comments) from their
BASIC programs so as to save space and increase execution speed. Whilst
this was obviously an appalling programming practice, the small memories
and slow microprocessors often made this tempting, if not necessary.

Thankfully, times have changed since then,
and most code is now compiled
rather than interpreted. However, from time to time one still runs into
an environment or situation, or special-purpose language, where comments
are either unavailable (no comment feature) or undesirable. Here
FunnelWeb can be used to fully document the code without resulting in any
comments in the final code at all. For example:\xx{header}{files}

\begin{itemize}

\item Comments in frequently used \p{.h} header files in C
programs\xx{C}{header} can
have a significant impact on compilation speed. Often such header files
are fairly cryptic and really ought to be well commented, but their authors
are reluctant to.

\item Comments are undesirable in PostScript\x{postscript}
header files that must be
transferred repeatedly along communications channels (\eg{}the Apple
Macintosh LaserWriter header file).

\item Interpreted programs in embedded systems.

\item Hand written machine code in hex dump form could be commented.

\item A programmer may wish to annotate a text data file containing lists
of numbers that is to be fed into a statistical program that does not
provide any comment facility for its input file.

\end{itemize}

In all these situations, FunnelWeb allows full integrated documentation
without any impact on the final code.

\subsection{Documents That Share Text}
\xx{sharing}{text}

FunnelWeb is very useful when preparing multiple documents that must
share large slabs of identical text that are being constantly modified.

For example someone preparing two slightly different user manuals for two
slightly different audiences might want the manuals to share
large slabs of text, while still allowing differences between them.
The following example shows how this can be done. The code is cluttered,
but this clutter would not be a problem if the lumps of text were moderately
large.

\begin{verbatim}
@O@<manual1.txt@>==@{@<M1@>@+@}
@O@<manual2.txt@>==@{@<M2@>@+@}

@$@<M1@>+=@{@<T1@>@}
@$@<M2@>+=@{@<T1@>@}
@$@<T1@>@M==@{First lump of text shared by both documents.@+@}

@$@<M1@>+=@{Text for first document@+@}
@$@<M2@>+=@{Text for second document@+@}

@$@<M1@>+=@{@<T2@>@}
@$@<M2@>+=@{@<T2@>@}
@$@<T2@>@M==@{Second lump of text shared by both documents.@+@}
\end{verbatim}

An alternative approach, which might work better in situations where there
are many small differences between the two documents rather than a few large
ones, is to define a macro with two arguments, one for each product
file document.
Write the document from top to bottom, but place all stretches that
differ between the two documents in a macro call.\xx{annual}{report}

\begin{verbatim}
@! Set the definition of @#D to
@!    @1 to create the shareholders report.
@!    @2 to create the customers report.
@$@#D@(@2@)@M==@{@1@}

@O@<report.txt@>==@{@-
1992 ANNUAL REPORT TO @#D@(Shareholders@,Customers@)
======================@#D@(============@,=========@)
This has been a very good year for The Very Big Corporation of America.
With your help, we have been able to successfully
@#D@(@"screw the customers for every cent they have@"@,
     @"knock the shareholders into submission to bring you lower prices@"@).
With gross earnings approaching six trillion dollars, we have been able to
@#D@(@"increase dividends@"@,
     @"lower prices@"@).
We expect to have an even better year next year.
@}
\end{verbatim}

One application where text sharing can be particularly useful is in the
preparation of computer documentation\xx{examples}{documentation}
containing examples. For example,
a book describing a new programming language might be full of examples
of small programs written in the language which the user might want to try
without having to type them all in. The \dq{default} approach of keeping
a copy of the examples in the text of the book and another copy in
separate files is cumbersome and error prone, because both files have to
be updated whenever an example is changed. A more sophisticated approach is
to store each example in a separate file, and then use the \dq{include file}
facility of the word processor to include each example in the text.
This is a better solution, but suffers from a few drawbacks. First, when
editing the book in a word processor, the
examples in the book will not be directly accessible or visible. To see an
example, the writer would have to open the file containing the example in
a separate window. This could become tedious if the text contained many
examples, as many texts do. Furthermore, there is a risk that some example
files will be included in the wrong place. Second, because the book is
dependent on the included files, the book will end up consisting of a
directory of a hundred or more files instead of just a few.

An alternative solution is to construct a single FunnelWeb \p{.fw}
file that, when processed, produces both the book file and the example files.
This solution assumes that the book consists of a text file containing
commands for a typesetter such as \TeX{}.

\begin{verbatim}
@O@<Book.tex@>==@{@#B@}

@$@#B+=@{@-
The first step to learning the object oriented AdaCgol++ language is to examine
a hello world program.

\start{verbatim}
@<Ex1@>
\finish{verbatim}
@}

@$@<Ex1@>==@{read iopack@+Enter !World~! !Hello~! ex pr flu X[1]@}
@O@<Ex1.c@>==@{@<Ex1@>@}

@$@#B+=@{@-
To understand the program, think of the execution state as a plate of cheese...
@}
\end{verbatim}

Most of the file will consist of part definitions of the additive
macro \p{@\#B}. The definition is \dq{broken} to allow a macro definition,
wherever an example appears.

The example above is a little messy because FunnelWeb does not allow
macros connected to product files to be called, and it does not have
text expressions that write to an product file as well as evaluating to text.
Nevertheless, it presents a fairly clean solution to the problem of keeping
the example programs in a computing text up to date.

\subsection{Generics}
\xx{generics}{fudging}

It is well known that generics in programming languages are closely aligned
with textual substitution. In fact, a good way to understand the generic
facility of a new programming language is to ask oneself the question
\dq{In what way does this generic facility differ from simple text
substitution?} The differences, if any, typically have to do with
the difference in scoping between textual and intelligent substitution
and whether the generic code is shared or copied by the implementation.
In most cases the differences are quite minor.

Because generic facilities are so closely aligned with text substitution,
it is possible to use FunnelWeb's parameterized macros to provide generics
in programming languages that do not support generics. Simply write a
FunnelWeb macro whose parameters are the parameters of the generic and
whose body is the generic object.

The following FunnelWeb file gives an example of a fully worked Vax
Pascal\x{Pascal}
generic set package implemented using FunnelWeb parameterized macros.
The package was written by Barry Dwyer\xn{Barry}{Dwyer}
of the Computer Science Department
of the University of Adelaide\xx{University}{Adelaide}
in 1987 and was emailed to me on
11~November 1987. The generic package provides a set
abstraction\xx{set}{abstraction} implemented
using linked lists. Note the clever use of the instantiation parameters in
type, function, and procedure names.

\begin{verbatim}
@$@<Generic Set Module@>@(@2@)==@{@-
@! @1 is the base type, @2 is the set type.
[inherit ('@1'), environment ('@2')]

module @2;

type  @2 = ^@2Record;
      @2Record = record
         Member: @1;
         Next: @2;
         end;

procedure Null@2 (var Result: @2);
begin new (Result);
Result^.Member := (- MaxInt)::@1;
Result^.Next := nil end;

function IsNull@2 (S: @2): boolean;
begin IsNull@2 := S^.Member::integer = - MaxInt end;

procedure ForEach@1 (S: @2; procedure DoIt (i: @1));
var   ThisS, NextS: @2;
begin ThisS := S;
while ThisS^.Member::integer <> - MaxInt do
   begin NextS := ThisS^.Next;
   DoIt (ThisS^.Member);
   ThisS := NextS end;
end;

function First@1 (S: @2): @1;
begin First@1 := S^.Member end;

function Is@1InSet (i: @1; S: @2): boolean;
   procedure TestEquals (j: @1);
   begin if Equal@1 (i, j) then Is@1InSet := true; end;
begin Is@1InSet := false; ForEach@1 (S, TestEquals); end;

function Includes@2 (S1, S2: @2): boolean;
var Result: boolean;
   procedure TestIfInS1 (i: @1);
   begin if Result then if not Is@1InSet (i, S1) then Result := false; end;
begin Result := true;
ForEach@1 (S2, TestIfInS1);
Includes@2 := Result end;

function Disjoint@2s (S1, S2: @2): boolean;
var Result: boolean;
   procedure TestIfInS1 (i: @1);
   begin if Result then if Is@1InSet (i, S1) then Result := false; end;
begin Result := true;
ForEach@1 (S2, TestIfInS1);
Disjoint@2s := Result end;

function Equal@2 (S1, S2: @2): boolean;
begin
Equal@2 := Includes@2 (S1, S2) and Includes@2 (S2, S1);
end;

procedure Insert@1 (i: @1; var S: @2);
var   This, Pred, Succ: @2;
begin
if not Is@1InSet (i, S) then
   begin
   Pred := nil; Succ := S;
   while Succ^.Member::integer > i::integer do begin
      Pred := Succ; Succ := Succ^.Next end;
   if Succ^.Member::integer < i::integer then begin
      new (This); This^.Next := Succ; This^.Member := i;
      if Pred <> nil then Pred^.Next := This else S := This;
      end;
   end;
end;

procedure Insert@1s (S1: @2; var S2: @2);
var   This, Pred, Succ: @2;
   procedure Add@1 (i: @1);
   begin Insert@1 (i, S2) end;
begin
ForEach@1 (S1, Add@1);
end;

procedure Remove@1 (i: @1; var S: @2);
var   Pred, This: @2;
begin
Pred := nil; This := S;
while not Equal@1 (This^.Member, i) do begin
   Pred := This; This := This^.Next end;
if Pred <> nil then Pred^.Next := This^.Next else S := This^.Next;
Dispose (This);
end;

procedure Dispose@2 (var S: @2);
var   Old: @2;
begin
while S <> nil do begin Old := S; S := S^.Next; Dispose (Old) end;
end;

end.
@}

@O@<NaryTreeSet.pas@>==@{@-
  @<Generic Set Module@>@(@"NaryTree@"@,@"NaryTreeSet@"@)@}
@O@<NaryTreeSetSet.pas@>==@{@-
  @<Generic Set Module@>@(@"NaryTreeSet@"@,@"NaryTreeSetSet@"@)@}
\end{verbatim}

A great advantage of the approach reflected in the above example is that
it allows the programmer to construct a generic object in a language that
does not supply generics, \i{with complete typesafety.}\xx{typesafe}{generics}
This contrasts to the
approach that might be used in a language such as C where the programmer
might choose to construct a \dq{generic} package by parameterizing a
package with pointers to \p{void}. The resulting package is
powerful but extremely untypesafe. Such a generic list package is used in the
code of FunnelWeb itself and caused no end of problems, as the compiler had
no way of telling if pointers to the correctly typed object were being
handed to the correct list-object/function combination.

The major disadvantage of the text generic approach is that it causes the
code of the generic object to be duplicated once for each instantiation.
Depending on the number and size of the instantiations, this may or may not
be acceptable.

Where the duplication of code is unacceptable, a hybrid approach may be
taken. As in the C~example, the programmer could write
a single generic package
using pointers to \p{void} or some other untypesafe mechanism.
Then the programmer
creates a FunnelWeb generic package whose functions do nothing
more than call the functions of the untypesafe package, and whose types do
nothing more than contain the types of the untypesafe package. This solution
involves the use of untypesafe programming, but this is a one-off
and if done carefully and correctly, the result can be
a typesafe generic package involving minimal code duplication.

\section{Summary}

This chapter has described some of the finer aspects of the use of FunnelWeb.
Throughout, the power and danger of FunnelWeb as a general text-rearranging
preprocessor has been emphasised. FunnelWeb can be used both to make programs
more readable or more obscure. It is up to the programmer to ensure that
FunnelWeb is used properly.

%==============================================================================%
%                               End of Ch2.tex                                 %
%==============================================================================%
