summaryrefslogtreecommitdiff
path: root/web/funnelAC/userman/u_ch2.tex
blob: f1abe0773b66d5725b33746f71c542aad011c991 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
%==============================================================================%
%                                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                                 %
%==============================================================================%