<< . .

. 27
( : 45)

. . >>

I forgot the underscore. Luckily this didn™t cause any harm; just
found an isolated expression, ˜mode.setup ™, which it will ignore. So let me now
insert the correct command, ˜mode setup™.”
Good thinking; so you type ˜I mode_setup™, right? Wrong . . . sorry. Lots
of error messages occur before has read a semicolon in preparation
for another statement; the important clue in this case comes from the two lines
<to be read again>
224 Chapter 27: Recovery from Errors

which tell us that the semicolon is still pending. So the correct response would Extra tokens will be ¬‚ushed
have been to type ˜I; mode_setup™ instead. Without the semicolon, you get semicolon
what appears at ¬rst to be a horrible mess: Unde¬ned coordinate
! Extra tokens will be flushed. typographic errors
<to be read again> OK
warningcheck dependent variable
independent variable
<insert> mode_setup

<to be read again>
l.1 mode setup;
% an intentional error!
But relax, there™s a simple way out. The help message says ˜Please insert a
semicolon now in front of anything that you don™t want me to delete™; all you
have to do is type ˜I;™ and the net e¬ect will be the same as if you had correctly
inserted a semicolon before mode_setup in the ¬rst place.
The moral of this story is: When you insert a new statement during
error recovery, you frequently need to put a semicolon just ahead of it. But if
you forget, gives you another chance.
After proceeding through badio with the interactions suggested in Chap-
ter 5, we will come again to the error
>> 0.08682thinn+144
! Undefined x coordinate has been replaced by 0.
(This is where the erroneous ˜thinn™ was detected.) The help message for this
error has some curious advice:
(Chapter 27 of The METAFONTbook explains that
you might want to type ˜I ???™ now.)
Chapter 27? That™s us! What happens if we do type ˜I ???™ now? We get
! OK.
It is now abundantly clear that ˜thin™ was misspelled. Plain de¬nes
˜???™ to be a macro that shows all of the current dependencies between numeric
variables and stops with ˜OK™; this is useful because a badly typed variable name
might have become a dependent variable instead of an independent variable, in
which case it would be revealed by ˜???™ but not by the error message.
Chapter 27: Recovery from Errors 225

One more example of online error correction should su¬ce to make the
general strategy clear. Suppose you accidentally type square brackets instead of
parentheses; the computer will scream:
! A primary expression can™t begin with ˜[™.
<inserted text>
<to be read again>
<*> show round[
1 + sqrt43];
(By coincidence, the help message for this particular error also refers to Chap-
ter 27.) When needs to see an expression, because of the tokens it
has already digested, it will try to insert ˜0™ in order to keep going. In this case
we can see that zero isn™t what we intended; so we type ˜7™ to delete the next
seven tokens, and the computer comes back with
<*> show round[1 + sqrt43]
Now ˜I (1 + sqrt43)™ will insert the correct formula, and the program will be
able to continue happily as if there were no mistake.
Why was ˜7™ the right number of tokens to delete?
If the user hadn™t deleted or inserted anything, but had just plunged ahead,
would have come up with another error:
>> 0
! Extra tokens will be flushed.
<to be read again>
<to be read again>
<to be read again>
<*> show round[1 + sqrt43]
Explain what happened. What should be done next?

It™s wise to remember that the ¬rst error in your program may well
spawn spurious “errors” later on, because anomalous commands can in¬‚ict se-
rious injury on ™s ability to cope with the subsequent material. But
226 Chapter 27: Recovery from Errors

most of the time you will ¬nd that a single run through the machine will locate batchmode
all of the places in which your input con¬‚icts with ™s rules. emergency stop
Sometimes an error is so bad that is forced to quit prematurely. Fatal base ¬le error
For example, if you are running in batchmode or nonstopmode, - loop
in¬nite loop
makes an “emergency stop” if it needs input from the terminal; this happens
I can™t go on
when a necessary ¬le can™t be opened, or when no end was found in the input. Here This can™t happen
are some of the messages you might get just before gives up the ghost: METAFONT capacity exceeded

Fatal base file error; I™m stymied.
This means that the preloaded base you have speci¬ed cannot be used, because it was
prepared for a di¬erent version of .
That makes 100 errors; please try again.
has scrolled past 100 errors since the last statement ended, so it™s probably
in an endless loop.
I can™t go on meeting you like this.
A previous error has gotten out of whack. Fix it and try again.
This can™t happen.
Something is wrong with the you are using. Complain ¬ercely.
There™s also a dreadful message that issues only with great reluc-
tance. But it can happen:
METAFONT capacity exceeded, sorry.
This, alas, means that you have tried to stretch too far. The message
will tell you what part of ™s memory has become overloaded; one of the
following eighteen things will be mentioned:
(strings and names of symbolic tokens and ¬les)
number of strings
(the characters in such strings)
pool size
(pairs, paths, pens, pictures, token lists, transforms, etc.)
main memory size
(symbolic token names)
hash size
(simultaneous input sources)
input stack size
(internal quantities)
number of internals
(transitions between octants in cycles)
rounding table size
(macro parameters)
parameter stack size
(characters in lines being read from ¬les)
buffer size
(input ¬les and error insertions)
text input levels
(key points per path)
path size
(rows of picture being simultaneously accessed)
move table size
(pen o¬sets per octant)
pen polygon size
(accumulated ligtable instructions)
ligtable size
(distinct kern amounts)
(built-up characters)
(largest headerbyte address)
(largest fontdimen address)
The current amount of memory available will also be shown.
Chapter 27: Recovery from Errors 227

If you have a job that doesn™t over¬‚ow ™s capacity, yet you want tracingstats
stack positions
to see just how closely you have approached the limits, just set tracingstats
memory usage
to a positive value before the end of your job. The log ¬le will then conclude with a recursion
report on your actual usage of the ¬rst nine things named above (i.e., the number of interrupt
in¬nite loops
strings, . . . , the bu¬er size), in that order. Furthermore, the showstats command can errorstopmode
be used to discover the current string memory and main memory usage at any time show
during a run. The main memory statistics are broken into two parts; ˜490&5950™ means,
for example, that 490 words are being used for “large” things like pens, capsules, and
transforms, while 5950 words are being used for “small” things like tokens and edges.
What can be done if ™s capacity is exceeded? All of the above-listed
components of the capacity can be increased, except the memory for kerns and
extensible characters, provided that your computer is large enough; in fact, the space
necessary to increase one component can usually be obtained by decreasing some other
component, without increasing the total size of . If you have an especially
important application, you may be able to convince your local system people to provide
you with a special whose capacities have been hand-tailored to your needs.
But before taking such a drastic step, be sure that you are using properly.
If you have speci¬ed a gigantic picture that has lots of transitions between black and
white pixels, you should change your approach, because has to remember
every change between adjacent pixel values in every currently accessible picture. If you
keep saving di¬erent pens, you might be wasting memory as discussed in Chapter 16. If
you have built up an enormous macro library, you should realize that has
to remember all of the replacement texts that you de¬ne; therefore if memory space is
in short supply, you should load only the macros that you need.
Some erroneous programs will over¬‚ow any ¬nite memory capac-
ity. For example, after ˜def recurse=(recurse)enddef™, the use of recurse
will immediately bomb out:
! METAFONT capacity exceeded, sorry [input stack size=30].
The same sort of error will obviously occur no matter how much you increase -
™s input stack size.
Most implementations of allow you to interrupt the program in
some way. This makes it possible to diagnose the causes of in¬nite loops,
if the machine doesn™t stop because of memory limitations. switches to
errorstopmode when interrupted; hence you have a chance to insert commands into
the input: You can abort the run, or you can show or change the current contents
of variables, etc. In such cases you will probably want to “hide” your diagnostic com-
mands, for example by typing
I hide(showstopping:=1; alpha:=2; show x)
228 Chapter 27: Recovery from Errors

so that you don™t mess up the expression is currently evaluating. Inter- strange
El Palo Alto
ruption can also give you a feeling for where is spending most of its time,
if you happen to be using an ine¬cient macro, since random interrupts will tend to for
occur in whatever place visits most often. octant
compass directions
™s second most frustrating error messages are its occasional claims
that you have “strange” paths. Sometimes a glance at your output will make ESE
it clear that you did indeed specify a path that crossed over itself, something like a WSW
¬gure-8; but sometimes a path that looks ¬ne to you will be rejected by the computer. NNE
In such cases you need to decipher ™s octant codes, which look scary at ¬rst NNW
although they turn out to be helpful when you get used to them. For example, let™s
reconsider branch4 of El Palo Alto, from the program in Chapter 14:
If the number 450 in the third ¬‚ex had been 452 instead, would have
stopped and told you this:
! Strange path (turning number is zero).
<to be read again>
<for(4)> ...]shifted(150,50)scaled(w/300);
p.4,l.94 endfor
The ˜for(4)™ in the ¬fth-last line implies that branch4 is at fault, because it says that
the for loop index is 4; but the octant codes like ˜SSW™ are your only clues about why
branch4 is considered strange. (A simpler example appeared in Chapter 13, which
you might want to review now.) You probably also have a proofmode diagram:

(Figure 27a will be inserted here; too bad you can™t see it now.)

Starting at time 0, and at the point (0, 509), the path goes South by Southwest, then
West by Southwest until time 2 (the end of the ¬rst ¬‚ex). Then it goes SSW again,
Chapter 27: Recovery from Errors 229

and WSW again (that™s the second ¬‚ex). But at time 4, the path makes a sharp turn counterclockwise
through the directions WNW and NNW, without moving (because these octant codes are
in parentheses). Aha! That™s where the path was supposed to turn counterclockwise, tracingspecs
through SSW and SSE and ESE; turned clockwise because it was the shortest tracingtitles
way to go. The path actually makes a little loop at time 4, between the end of the tracingrestores
second ¬‚ex and the beginning of the third. Therefore its turning number is indeed zero, tracingequations
and the path is strange by de¬nition.
control points
At what point do the second and third ¬‚exes cross, in this example?
There are three main ways to avoid problems with strange paths. One is to
stay away from paths that turn so abruptly. Or you can displace the paths by
epsilon , as in the serif example at the end of Chapter 16. (Displacing by eps would be
even safer.) Or you can discipline yourself to ¬ll all cycles counterclockwise, so that
you can set turningcheck := 0; this means that won™t check for strange
paths, but that™s OK because tiny little loops won™t hurt anything if you are ¬lling
cycles in the correct direction.
Sometimes the octant codes of a strange path are shown backwards, because
the system may have tried to reverse the path to get rid of its strangeness.
Sooner or later”hopefully sooner”you™ll get to process
your whole ¬le without stopping once to complain. But maybe the output still
won™t be right; the mere fact that didn™t stop doesn™t mean that
you can avoid looking at proofsheets. At this stage it™s usually easy to see how
to ¬x typographic errors by correcting the input; hardcopy proofs such as those
discussed in Appendix H usually clear up obvious mistakes, especially if you have
remembered to label the key points in your constructions.
But your output may contain seemingly inexplicable errors. If you can™t
¬nd out what went wrong, try the old trick of simplifying your program: Remove
all the things that do work, until you obtain the shortest possible input ¬le that
fails in the same way as the original. The shorter the ¬le, the easier it will be
for you or somebody else to pinpoint the problem.
One of the important tricks for shortening a buggy program is to assign a
positive value to tracingspecs , because this will put all the key points and
control points of a problematic path into your log ¬le. (See the example at the end
of Chapter 24, “before subdivision.”) If something is wrong with the treatment of
some path, you can copy the path™s description from the log ¬le and use it directly in
input, thereby avoiding all the complexity of equations that might have
been involved in that path™s original creation.
We™ve just talked about tracingstats and tracingspecs ; is able
to produce lots of other kinds of tracing. For example, Chapter 22 discusses
tracingtitles , Chapter 18 discusses tracingmacros , Chapter 17 discusses tracingrestores ,
and Chapter 9 discusses tracingequations . You can also invoke tracingchoices , which
shows all paths before and after their control points are chosen according to the rules in
Chapter 14; or tracingpens , which shows the pen polygons that arise when a future pen
becomes a full-¬‚edged pen; or tracingoutput , which shows every picture that™s shipped
230 Chapter 27: Recovery from Errors

out, using edge-transitions to represent the pixel values as illustrated in Chapter 13. interim
Each of these types of tracing is enabled by assigning a positive value to the correspond-
ing internal quantity; for example, you can simply set tracingpens := 1 (or interim expandable token
tracingpens := 1) if you want the data about pens. algebraic
Digitized output
If tracingcommands = 1, shows every command just before it is tracingedges
carried out. If tracingcommands = 2, also shows every expand- lowres
able token just before it is expanded (except that macros are separate, they™re traced
only when tracingmacros > 0). And if tracingcommands = 3, also shows ¬lldraw
every algebraic operation just before it is evaluated. Thus you can get “stream of octant
consciousness” information about everything is doing.
Digitized output can be monitored by setting tracingedges = 1. For example, tracingall
if we ask to draw the Ionian ˜ ™ of Chapter 5 at a resolution of showstopping
100 pixels per inch (lowres mode with mag = .5), tracingedges will report as follows:
Tracing edges at line 15: (weight 1) tracingnone
Tracing edges at line 15: (weight -1)

By following these edges (and negating their weights on the inner boundary) we ¬nd
that the character at this low resolution is symmetric:

Further information about digitization comes out when tracingedges > 1, if
¬xed pens are used to draw or ¬lldraw a shape. In this case detailed informa-
tion is presented about the activity in each octant direction; straight line “transition”
edges are also reported whenever changes from one peno¬set to another.

The tracing . . . commands put all of their output into your log ¬le, unless the
tracingonline parameter is positive; in the latter case, all diagnostic informa-
tion goes to the terminal as well as to the log ¬le. Plain has a tracingall
macro that turns on the maximum amount of tracing of all kinds. It not only sets up
tracingcommands , tracingedges , tracingspecs , and so on, it also sets tracingonline := 1,
and it sets showstopping := 1 so that you can do interactive debugging via show com-
mands. This is the works. There™s also loggingall, which is like tracingall except
that it doesn™t touch tracingonline or showstopping . You can say interact if you want
just tracingonline := showstopping := 1. Finally, there™s tracingnone, which shuts o¬
every form of tracing after you™ve had enough.

Some production versions of have been streamlined for speed.
These implementations don™t look at the value of tracingstats , nor do you
get extra information when tracingedges > 1, because runs faster when it
doesn™t have to maintain statistics or keep tabs on whether tracing is required. If you
want all of ™s diagnostic tools, you should be sure to use the right version.
Chapter 27: Recovery from Errors 231

If you set pausing := 1, will give you a chance to edit each line of pausing
input as it is read from the ¬le. In this way you can make temporary patches
(e.g., you can insert show. . . commands) while troubleshooting, without changing the FONT
actual contents of the ¬le, and you can keep running at human speed. HEIN

Final hint: When working on a large font, it™s best to prepare only a
few characters at a time. Set up a “test” ¬le and a “master” ¬le, and do your
work in the test ¬le. (Appendix E suggests a convenient way to prepare control
¬les that supply parameters to individual test characters as well as to the whole
font.) After the characters come out looking right, you can append them to the
master ¬le; and you can run the master ¬le through occasionally, in
order to see how the font is shaping up. Characters can always be moved back
to the test ¬le if you have to ¬x some unexpected problems.

<< . .

. 27
( : 45)

. . >>